CRUD methods in custom Swift classes - ios

I'm wondering if it's a good idea to include CRUD methods inside custom Swift classes, or are they better off in a separate class?
For example I have a class called User.swift:
class User {
var firstName: String
var lastName: String
var id: int
}
Now, would it be okay to include the get and create methods here? These methods will make API calls via Alamofire:
class User {
var firstName: String
var lastName: String
var id: int
static func add(user: User) -> User {
let parameters = ["firstName": user.FirstName , "lastName": user.LastName]
return sendRequest(.POST, url: "example.com/users", parameters: parameters)
}
static func getById(userId: Int) -> User {
return sendRequest(.GET, url: "example.com/users/\(userId)")
}
}
Should these methods be in a separate class, like in an ApiHelper class?
My application passes around the User object in arrays and dictionaries in several places, so wondering if it's good to keep it clean with just the properties.

I think better declare such methods in some ApiHelper/Router singletone class, as well as they must work async, work with some parse system (RestKit probably) and return fetched objects via closures with some delay

The different opinions about the right approach often causes a heated discussion. And this also extends to questions whether we should perform validation in the model class (User) or in the controller, how we should handle versions, serialisation, errors, undo/redo, locking, asynchronicity, etc., etc.
And the resulting code should still be clean, comprehensible, extensible, testable and put into a library so that we can reuse it in other projects!
IMHO, there's no right approach. IMHO, I would start with the following principles:
Your User class is seen in your solution as an Entity. An entity has a property ID and possibly other principal methods, for example, it exposes an init which takes a dictionary of attributes where the class/struct instance can be initialised.
That entity also knows about a "Persistent Store", so your User class may also conform to a protocol "Storable", which exposes class and instance methods like save, create, update, delete, query, etc.
This is only the tip of an iceberg what comprises a complete solution. You might look how others have solved this problem. For ideas, see
Use Core Data objects which you populate from the JSON
Implement the Active Record Pattern
Look at some Object Relational Mappers (there are a lot of implementations and libraries). Even though, you need to map from JSON to Objects, these gives some hints.
If you are still not satisfied, take a look at ASP.NET
Leveraging the "Active Record" approach you may start with something like this:
public final class User {
public init(firstName: String, lastName: String) {
self.firstName = firstName
self.lastName = lastName
}
public var firstName: String
public var lastName: String
public internal(set) var id: Int
}
protocol ActiveRecord {
static func create(object: Self) throws -> Self
static func fetch(id: Int) throws -> Self
static func update(object: Self) throws -> Self
static func delete(id: Int) throws
}
extension User: ActiveRecord {
static func create(object: User) throws -> User {
...
}
static func fetch(id: Int) throws -> User {
...
}
static func update(object: User) throws -> User {
...
}
static func delete(id: Int) throws {
...
}
}

Related

Testing protocol extension with default implementations

In past projects, I've had an object use constructor injection for the objects it needs to get some other information. For example:
class Foo {
let appInfo: AppInfoType
init(appInfo: AppInfoType) {
self.appInfo = appInfo
}
}
protocol AppInfoType {
func build(bundle: Bundle) -> String?
}
And then if within Foo, information about the app like build is needed, it can use AppInfoType to get that info. I thought I would see what this looked like with protocol extensions.
extension AppInfoType {
func build(bundle: Bundle) -> String? {
return bundle.infoDictionary?[kCFBundleVersionKey as String] as? String
}
}
class Foo: AppInfoType {
}
So now I can achieve the same thing within Foo by just calling build(bundle: Bundle.main). But is there any easy way to test this now? With the first way, I could still create a MockAppInfoType and provide an implementation for build(bundle: Bundle), but now I don't really see a way to do this unless the protocol extension maybe depended on another protocol where I could inject a mock for that protocol.

How can I allow my function to accepts two different objects in swift?

I have a function which takes one argument. I wanted my function to accept two object types. How can I do it? Here is the example below:
func accept(user: Customer) {
...
}
It should accept Customer and Employee object reference.
accept(objRefCustomer)
accept(objRefEmployee)
Please help me in this case.
Alternative to super-classing: use protocols
You needn't necessarily use a superclass for this case (if Customer and Employee are struct value types; superclass option is not possible), but can rather use the more generic approach of protocols.
Define a protocol Users which blueprints properties and methods for your Customer and Employee instances (if we let Customer and Employee conform to Users, then we promise that instances of these two structures will have accessible the blueprinted properties and methods):
protocol Users {
var name: String { get }
func printTypeOfUser()
}
Define the Customer and Employee structures, and their conformance to the protocol Users:
struct Customer : Users {
let name: String
init(name: String) { self.name = name }
func printTypeOfUser() {
print("Is a Customer!")
}
}
struct Employee : Users {
let name: String
let id: Int
init(name: String, id: Int) { self.name = name; self.id = id }
func printTypeOfUser() {
print("Is an Employee!")
}
}
Now you can define a generic function where its generic, say T, is type constrained to types conforming to the protocol Users, which in this case is equivalent to the Customer or Employee types
func accept<T: Users>(user: T) {
print("Name of user: \(user.name) [\(user.dynamicType)]")
user.printTypeOfUser()
// do something additional employee-specific if user is an employee?
if let employee = user as? Employee {
print("User is an employee with id: \(employee.id)")
}
}
Example usage of this function for Employee as well as Customer instances:
let employee = Employee(name: "John", id: 1)
let customer = Customer(name: "Sarah")
accept(employee) /* Name of user: John [Employee]
Is an Employee!
User is an employee with id: 1 */
accept(customer) /* Name of user: Sarah [Customer]
Is a Customer! */
Instead of changing your Class structure and code base, you can use AnyObject. It will also be easier for you if, for example, in future you have to make this function accept parameters of class WaterMelon. Making all these classes inherit from a common parent class would be unnecessary overhead, not to mention hectic.
AnyObject is swift equivalent of objective c id. AnyObject is a protocol that can represent an instance of any class type.
It also has a more general counterpart, Any, which can represent any type at all (including structs and enums).
Following code will accept any class type parameter you pass:
func accept(sender : AnyObject) { //Or AnyObject? if you want to handle nil as well
...
}
To access properties of the classes you pass as AnyObject, you can use type casting.
For example below code will check sender type and typecast it for you:
if let customerRef = sender as? Customer {
// ...
// Sender is of customer class type. Use it with customerRef that we created
let customerName = customerRef.dynamicType.sampleNameProperty //Access a property of class Customer
customerRef.funcOfCustomerClass() //Call a method of class Customer
}
else{
//Sender is not of customer class type.
//Then it must be Employee??? Handle cases for employee here.
}
create a protocol, and use it as argument type. protocol can be also empty, it will work anyway. Works with struct and class as well;
ex:
protocol SomeFakeProtocol {}
class SomeClass: SomeFakeProtocol { //code here }
struct SomeStruct: SomeFakeProtocol { //code here }
func someFunction(arg: SomeFakeProtocol) { //code here }
Benefits - you can allow to use only types you want to. And, sure, you can do things like this:
extension String: SomeFakeProtocol {}
You can create a super class called People of Cutomer and Employee.
Then set user as type of People:
func accept(user: People) {
...
}
You don't need a super class, you can just pass an object of type AnyObject and in your function check the type of the object passed:
func accept(user: AnyObject) {
if let usr = user as? Person {
...
}
}
But if you have many types you want to pass you may want to make a protocol or a super class.

Where to put reusable functions in IOS Swift?

New to IOS programming but just wondering where is the best place to put functions that I would use throughout my code. For example, I want to write a few functions to perform a POST request to a web service and return a dictionary. Maybe another function to do some calculations. Is it best to create another .swift file and put all my functions there. And what would be a good name to give the file if so?
public func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
The best way is to create a helper class with static functions, like this:
class Helper{
static func postRequest() -> [String:String] {
// do a post request and return post data
return ["someData" : "someData"]
}
}
Now every time you need to use postRequest you can just use like so: Helper.postRequest()
I usually create a separate class if I have functions that will be used by multiple classes, especially for the ones involving network operations.
If you just have separate functions that will be used, you can simply create static functions inside that class so it is easily accessible by other classes in a static way:
class DataController {
static func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.getData() // example
However, what often has been the case for me (especially if it involves more complicated operations) was that these network operations needed to establish an initial connection beforehand or required some initial setups, and they also performed asynchronous operations that needed to be controlled. If this is the case and you will often be calling such methods, you might want to create a singleton object that you could use throughout different classes and functions. This way, you could do the initial setup or establish an initial connection just once, and then do the rest as needed with the other functions, instead of doing them every time the function gets called.
Creating a singleton object is pretty simple in Swift:
class DataController {
static let sharedInstance = DataController() // singleton object
init() {
// do initial setup or establish an initial connection
}
func getData() -> [String:String] {
// do some operations
return ["someData" : "someData"]
}
}
let data = DataController.sharedInstance.getData() // example
For the name of the class, I usually name it something like DataController or DataHelper, but anything that makes sense as a "helper" class would work.
Hope this helps :)
For reusable functions it depends what I decide to use. For this specific case I use a separate file, because posting to a backend will become more complicated when the application evolves. In my app I use a backend class, with all kinds of helper classes:
struct BackendError {
var message : String
}
struct SuccessCall {
var json : JSON
var containsError : Bool {
if let error = json["error"].string {
return true
}
else {
return false
}
}
}
typealias FailureBlock = (BackendError) -> Void
typealias SuccessBlock = (SuccessCall) -> Void
typealias AlamoFireRequest = (path: String, method: Alamofire.Method, data: [String:String]) -> Request
typealias GetFunction = (path: String , data: [String : String], failureBlock: FailureBlock, successBlock: SuccessBlock) -> Void
class Backend {
func getRequestToBackend (token: String )(path: String , data: [String : String], failureBlock: FailureBlock, successBlock:
}
For other cases I often use extensions on Swift classes. Like for getting a random element from an Array.
extension Array {
func sampleItem() -> T {
let index = Int(arc4random_uniform(UInt32(self.count)))
return self[index]
}
}
This very old question but I would like to chirp some more points.
There are a few option, basically you can write your utility functions in Swift -
A class with static function. For example
class CommonUtility {
static func someTask() {
}
}
// uses
CommonUtility.someTask()
Also, you can have class method's as well instead of static method but those functions can be overridden by subclasses unlike static functions.
class CommonUtility {
class func someTask() {
}
}
// uses
CommonUtility.someTask()
Secondly, you can have Global functions as well, that are not part of any class and can be access anywhere from your app just by name.
func someTask() {
}
Though, selecting one over other is very subjective and I thing this is ok to make a class with static function in this particular case, where you need to achieve networking functionality but if you have some functions which perform only one task than Global function is a way to go because Global functions are more modular and separate out single tasks for a single function.
In case of static functions, if we access one of the static member, entire class gets loaded in memory. But in case of global function, only that particular function will be loaded in mem
You can create a separate swift class, might name it WebServicesManager.swift, and write all methods related to web requests in it.
You can use class methods, or singleton pattern to access the methods.

How to reference a class that follows a protocol in return type of function?

I have a protocol called Social Service, declared as follows:
protocol SocialService: class {
class func testFunc()
}
A class that follows the protocol may look like this:
class Twitter: SocialService {
class func testFunc() {
}
}
I want to have a method which returns a class that follows this protocol, so calling it would look like this:
let socialService = socialServiceForServiceType(serviceType: String)
I'm not sure what I need to put as the return value type of this function. For example, this:
func socialServiceForServiceType(serviceType: String) -> SocialService.Type
doesn't give an error right here, but trying to call it as above, gives an error:
Accessing members of protocol type value 'SocialService.Type' is
unimplemented
EDIT: I don't want an instance of that type, I want a class of that type. So I want a Twitter class, so I can call the class methods from the SocialService protocol on it.
Like the error says, this feature is unimplemented. However...
I don't want an instance of that type, I want a class of that type. So I want a Twitter class, so I can call the class methods from the SocialService protocol on it.
I'm not sure what you think you're getting from avoiding instances like this. Bear in mind classes don’t need to have member variables, and without them are essentially just collection of function pointers – which is what you seem to be looking for.
If you implement a Twitter class that has no properties and that conforms to a protocol, then calling methods on that protocol will dynamically dispatch to the implementations of that instance:
protocol SocialService: class {
func testFunc()
}
class Twitter: SocialService {
func testFunc() {
println("Testing Twitter!")
}
}
func socialServiceForServiceType(serviceType: String) -> SocialService {
return Twitter()
}
let service = socialServiceForServiceType("blah")
// prints "Testing Twitter!"
service.testFunc()
If your concern is that you want to put member variables in the Twitter class, but don’t want the overhead of that for some features, then this probably suggests you want to decompose this functionality into two different classes. Alternatively, if you want a singleton instance (to handle the connectivity for example) then there are other patterns to handle this.
Use simply
func socialServiceForServiceType(serviceType: String) -> SocialService
A protocol can be the return type of a function.
Totally agree with Airspeed Velocity, but I'd like to expand on one of his points:
I'm not sure what you think you're getting from avoiding instances like this. Bear in mind classes don’t need to have member variables, and without them are essentially just collection of function pointers – which is what you seem to be looking for.
I assume you're trying to do something like this:
func socialServiceForServiceType(serviceType: String) -> SocialService.Type
...
let cls = socialServiceForServiceType("twitter")
let conn = cls.connect(user)
Or something like that. You don't need classes to achieve that. You can just return functions.
typealias Connect = User -> Connection
func connectorForServiceType(serviceType: String) -> Connect {
switch serviceType {
case "twitter": return Twitter.Connect
...
}
}
let connect = connectorForServiceType("twitter")
let conn = connect(user)
If you have a whole bundle of functions that you want to package together, just use a struct.
struct ServiceHandlers {
let connect : User -> Connection
let ping : () -> Bool
let name: () -> String
}
func standardPinger(host: String) -> () -> Bool {
return { host in
// perform an ICMP ping and return Bool
}
}
func handlersForServiceType(serviceType: String) -> ServiceHandlers {
switch serviceType {
case "twitter":
return ServiceHandlers(connect: Twitter.connect,
ping: standardPinger("www.twitter.com"),
name: { "Twitter" })
...
}
}
let service = handlersForServiceType("twitter")
let conn = service.connect(user)
In some ways this is duplicative with class methods, but (a) the features you need for class methods aren't implemented, and (b) this is much more flexible. You can return any collection of functions you want; they don't have to all be class methods. It's easier to have default behaviors (which are hard in Swift when you use inheritance). It's easier to extend because you don't necessarily have to extend all the classes (see my use of standardPinger, which is some function I've made up that returns another function; it doesn't have to be a class method).
Breaking free of class/inheritance thinking and just passing around functions can be a major benefit in Swift. Sometimes a struct is better than a protocol.
Use a Factory pattern to achieve the same.
class SocialFactory : NSObject
{
class func socialServiceForServiceType(serviceType: String) -> SocialService?
{
switch serviceType
{
case "Twitter":
return Twitter();
case "Facebook":
return Facebook()
default:
return nil;
}
}
}

ActiveRecord like reflection in swift

I was wondering how to accomplish an active record like (not with core data, but with rest, but this part I don't think will be an issue).
The issue its that don't understand well the reflection in swift, and my goal its to have a base class called Collection like (just prototype not really working code here):
public class Collection
{
public var Id: String
public static func Name () -> String
{
// accomplished but not with static method
}
public static func Find () -> [ChildClass] // the child class how can I obtain dynamically?
{
// restful things
return [ChildClass, ChildClass, ...] // rest result maped from json
}
public static func FindById (id : String) {}
// also Save && Delete methods
}
This kind of things I accomplish in c# with WSD-Data exactly in this class
So the usage maybe will:
public class User : Collection
{
public var FirstName: String
public var LastName: String
}
or c# like (dunno if this can be done in swift)
public class User : Collection<User> // we pass user as reference class c# like
{
public var FirstName: String
public var LastName: String
}
I hear also other alternatives to get this done, because don't know so well swift and the way that things are done with it.

Resources