Tips to boost your iOS work
Tags: ios, iostips
Published: 2020-04-28 21:19:34

Some tips below help me work faster and more efficiently. Let's check it out. 

# 1. Don't depend on server API. 

APIs are immensely important and we can't do anything without APIs. So can we watch Youtube or Facebook while backend teams are burying their noses in code? 
You will get a red alert from your manager soon. 
Or APIs are slow and hard for us to test while developing it. What should we do? 

`Don't depend on server API. Just depend on the schemas.`
- Ask backend for API schemas, which they send to us when we call. Save it into a json file. 
- Use tip #2 or #3 to create your data model.
- Setup your code as you're calling API. I usually seperate API calls to workers. You can do your way. 

```
class GetUserDetailWorker {
// (1)
    func run(completion: @escaping(User?, Error?) -> Void) {
        Alamofire.request() {
            handleResponse(response: AnyObject, completion: completion)
        }
    }

// (2)
    private func handleResponse(response: AnyObject?, completion: @escaping(User?, Error?) -> Void) {
        // parse json to your data model
        // check logic
        // ...
        // call completion
    }
}
```
(1): Your controllers don't know what is inside the `GetUserDetailWorker`. They respond to success or failure from the worker. So, you are free to fake any data here and see how your controllers respond to. 

(2): This is where you parse raw json to your data model, handle the logic and response.

Now do a trick. 

Add function after your `handleResponse` function. 
```
func loadLocally(completion: @escaping(User?, Error?) -> Void) {
    if let filepath = Bundle.main.path(forResource: "User", ofType: "json") {
        do {
            let contents = try String(contentsOfFile: filepath)
            let data = contents.data(using: .utf8)!
            if let json = try JSONSerialization.jsonObject(with: data, options : .allowFragments) as AnyObject? {
                handleResponse(response: json, completion: completion)
                } else {
                    print("bad json")
                }
        } catch {
            completion(nil, error)
        }
    }
}
```

Add this at the begining of `run` function. 
```
loadLocally(completion: completion)
return
```

We load the `user.json` and send it to controllers. It's on your computer, we can change any data as we want. When APIs are ready, just remove these 2 lines and work like a charm. 

## Some advantages 
- Fast. You call it from your computer, no delay or depend on internet. 
- Convenient. You can change any data you want, good cases, bad cases and change your UI approriately. 
- Independent. You don't depend on server progress anymore. 

# 2. Create init function
When you define `struct`, Swift can give you an `init` function, you don't have to write it yourself. But if you use `class`, no free `init`. What if you have a long class and long `init`, like below. 
```
class User {
    var id: String
    var tasks: [String]
    var email: String?
    var membershipExpirationDate: Date?
    var startDate: Date?
    var cancelAtPeriodEnd: Bool?
    var balance: Int
    let phoneNumber: String?
    let currency: String
    init(id: String, tasks: [String], email: String?, membershipExpirationDate: Date?, startDate: Date?, cancelAtPeriodEnd: Bool?, balance: Int, phoneNumber: String?, currency: String) {
        self.id = id
        self.tasks = tasks
        self.email = email
        self.membershipExpirationDate = membershipExpirationDate
        self.startDate = startDate
        self.cancelAtPeriodEnd = cancelAtPeriodEnd
        self.balance = balance
        self.phoneNumber = phoneNumber
        self.currency = currency
    }
}
```
Do you want to type it yourself? Try this way. 
![](https://firebasestorage.googleapis.com/v0/b/blogs-1de93.appspot.com/o/assets%2Fsublime%2Finit_function.gif?alt=media&token=6b2fbd14-3dbf-4564-ab6f-a58ee5b8a746)

**Notes**
- Press `option` and drag to select multiline.
- Delete unused words.
- Copy properties' name.
- Press `esc` to quit multi cursors. 

# 3. Parse JSON result
I am not a fan of `Codable`. It's really useful in simple responses, but complicated ones, no thanks. And it's hard to debug also. 

Most of work, I parse JSON manually, don't use `SwiftyJSON` or similar ones. One time, I joined a team with complicated responses. Example is below. 

```
{
  "Id": "b206bb24-03ab-4a25-a9c4-b26e2fd2e9f8",
  "Name": "Hexagon 21",
  "ScreenName": null,
  "Picture": "https://scontent.xx.fbcdn.net/v/t1.0-9/20245457_303012200102286_1324449236613079430_n.jpg?_nc_cat=104&_nc_oc=AQmRtf3n0fmK36Z8Vnzz5QFECni4m52YHbm0GbzdSEI6slVpgf59oGBHZCeOBv3yzGc&_nc_ht=scontent.xx&oh=24ebc12ea4244757e584f7f438e06e44&oe=5E613D7C",
  "ExternalId": "575475522634796",
  "FacebookUserId": null,
  "Account": null,
  "Type": 1,
  "Subtype": "FacebookGroup",
  "IsDefault": false,
  "Credential": null,
  "AssociatedSource": null,
  "PublishMessageProfiles": null,
  "ProfileSubscribeNotifications": null,
  "Selected": false,
  "HasAppInstalled": null,
  "IsWebHookSubscribed": false,
  "IsTwitterWebHookSubscribed": null
}
```
Now, making a class from these is a boring work. 
- Use this: [https://app.quicktype.io/](https://app.quicktype.io/).
- Explore options on the right pane to see it changes. 
And here the result: 
```
class User {
    var id: String?
    var name: String?
    var screenName: NSNull?
    var picture: String?
    var externalID: String?
    var facebookUserID: NSNull?
    var account: NSNull?
    var type: Int?
    var subtype: String?
    var isDefault: Bool?
    var credential: NSNull?
    var associatedSource: NSNull?
    var publishMessageProfiles: NSNull?
    var profileSubscribeNotifications: NSNull?
    var selected: Bool?
    var hasAppInstalled: NSNull?
    var isWebHookSubscribed: Bool?
    var isTwitterWebHookSubscribed: NSNull?

    init(id: String?, name: String?, screenName: NSNull?, picture: String?, externalID: String?, facebookUserID: NSNull?, account: NSNull?, type: Int?, subtype: String?, isDefault: Bool?, credential: NSNull?, associatedSource: NSNull?, publishMessageProfiles: NSNull?, profileSubscribeNotifications: NSNull?, selected: Bool?, hasAppInstalled: NSNull?, isWebHookSubscribed: Bool?, isTwitterWebHookSubscribed: NSNull?) {
        self.id = id
        self.name = name
        self.screenName = screenName
        self.picture = picture
        self.externalID = externalID
        self.facebookUserID = facebookUserID
        self.account = account
        self.type = type
        self.subtype = subtype
        self.isDefault = isDefault
        self.credential = credential
        self.associatedSource = associatedSource
        self.publishMessageProfiles = publishMessageProfiles
        self.profileSubscribeNotifications = profileSubscribeNotifications
        self.selected = selected
        self.hasAppInstalled = hasAppInstalled
        self.isWebHookSubscribed = isWebHookSubscribed
        self.isTwitterWebHookSubscribed = isTwitterWebHookSubscribed
    }
}
```
Pretty cool, right? 

# Conclusion 

Some tips from my experience. Hope them help you work faster and more interesting your work. 

> Enjoy coding