Codementor Events

Tips to boost your iOS work

Published Apr 07, 2020Last updated Apr 28, 2020

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.

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.

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

Discover and read more posts from Ky Nguyen
get started