Point of Synchronization in Swift - The Interview Problem

The iOS interview Series

Subscribe to my newsletter and never miss my upcoming articles

Hello Queens and Kings, Leo here.

Today I'll start one series about everything related to iOS interview process. The history started here: the Babylon health iOS github . There you can see that shared all theirs interviewing process and I could think some insights to share, this post is dedicated to one of the requirements for the Babylon iOS interview demo project.

The demo project consists of a list of photos. Upon tapping any photo, the user is taken to the photo detail screen. When a photo is tapped, you should go to the Photo detail screen. Also, a photo that is marked favourite shows up first in the list followed by other photos.

The project requirements are: should be Swift 5, stutter and crash free UI, the information should be available offline ( so you will have to use some persistence structure), and goes on. But one of those requirements pop into my eyes and it was "Have a point of synchronization (e.g. making two concurrent requests and waiting for both of them to finish)." . Well, that's interesting but how can we do that?

I recommend for everyone go check that GitHub project specifically the Interview questions part. There you can prepare for other iOS interview process and be more confident in your next interviewing process.

My 5 cents about interview process that I always keep in mind is that is a 2-way process. The company are assessing you as a possible future employee but you too are getting information about it to make a informed decision if it's a great company to work or if it's not fit for your purposes.

The painting I choose is The 1821 Derby at Epsom is an 1821 painting by Théodore Géricault, representing all the threads running asynchronously but all the bets will only be paid when all the horses completed their track, the final point of synchronization.

No more talk, let's code.

Problem

You have an interview demo project and are asked to have a point of synchronization in it.

The first sight might be overwhelming of this requirements. Should I handle multiple generic calls? Should I synchronize the persistence part? Should I make the sync process in background doing the screen diff outside the main thread and after that set the UI? Well, all that questions are valid but I came to a very simplistic solution to this. Remember this post about DispatchGroup ? Apple already solved this requirement for us with the Dispatch Framework , aka GCD . The dispatch group can synchronize anything you want, including asynchronous network calls.

Imagine that you have to asynchronously call the FAANG sites ( Facebook, Amazon, Apple, Netflix, Google) and you also want to do some action only after all the network calls have returned :

let dispatchGroup = DispatchGroup() // 1
let endpoints = [URL(string: "https://www.facebook.com")!,
                 URL(string: "https://www.amazon.com")!,
                 URL(string: "https://www.apple.com")!,
                 URL(string: "https://www.netflix.com")!,
                 URL(string: "https://www.google.com")!]

First (mark 1) we have to create a dispatchGroup to handle the point of synchronization.

This will be the point of synchronization of our example:

endpoints.forEach {
    let request = URLRequest(url: $0)
    dispatchGroup.enter() // 1 
    URLSession.shared.dataTask(with: request) { (_, response, _) in
        print(" endpoit completed = \(response?.url?.absoluteString ?? "")" )
        dispatchGroup.leave() // 2 
    }.resume()
}

dispatchGroup.notify(queue: .main) {
    print("All requests ended") // 3
}

print("All request started") // 4

Mark 4 is executed first because the requests didn't had the time to complete and as our code is asynchronous, it would continue until the end of the func.

On mark 1 you will enter in a async context managed by a dispatchGroup. DispatchGroups allow you to aggregate a set of tasks and synchronize behaviors on the group. You attach multiple work items to a group and schedule them for asynchronous execution on the same queue or different queues. When all work items finish executing, the group executes its completion handler. You can also wait synchronously for all tasks in the group to finish executing. And on mark 2 you leave that context managed by the DispatchGroup.

The mark 3 is the real point of synchronization. When the dispatch group enter that closure is guaranteed that all the group enters already has leave, this way in your code you can just take an action, after all the calls completed.

The result of te code above is:

Screen Shot 2021-03-25 at 11.08.36.png

And that's it!

Exploring DispatchGroups

The order of execution can be controlled using DispatchWorkItem, so the work you want to perform are encapsulated in a way that lets you attach a completion handle or execution dependencies.

Conclusion

To answer the requirement you don't need to use complex structures or go too far just to impress. It's always important that readability and easy to maintain code are far more important than clever code. When we write code, we never write for ourselves, we write a letter to someone in the future ( sometimes that person in the future is you, but who knows?).

I hope you all enjoy this and if you have any comment please share below. I want to know what do you think about it and most important what I can improve here.

If you want really good books about general programming just go to the support section, where you can find the most useful books for developers that I read and you will help me buying from those links.

Thanks for the reading and... That's all folks.

credits: image

No Comments Yet