Mastering Concurrency in iOS - Part 3 (Dispatch Group, Dispatch Work Item)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
foreign and this is the third video of our series on concurrency that is mastering concurrency in iOS in the first two videos we saw that what is concurrency concurrency versus parallelism how it is achieved in iOS the multi-threading stuff dispatch queue serial queues versus concurrent ones synchronous executions versus asynchronous execution quality of services some advanced concepts like Target queues and and everything around those while we have discussed quite a step we are yet to see dispatch groups dispatch work item dispatch work item Flags Sim offers operation queues and the latest in concurrency the task actors and all those we would be covering all of these in this series but after first two videos I got the feedback that videos are getting a little long so from now on I'll keep the video short I'll break the content in in more number of videos but the duration will be short so in today's video we are going to see dispatch group and dispatch work item in detail let's get started so we dispatched queues we saw that we can execute multiple tasks asynchronously and concurrently but what if you want to group those tasks together and want to get a call back when all of them are completed this is a very common situation that we face in our day-to-day work for example on Splash we want to make multiple API calls and want to proceed to the home screen the onwarding screen only when all of them have have completed their execution or maybe we want to download multiple images together and proceed when downloading of all of them has completed or let's say that you are fetching something from database or maybe from from some API and at the same time you are showing a progress indicator and you want to proceed only when the the animation of that progress and the downloading has completed so basically whenever you want to group multiple tasks together be two or more than two and then proceed with an action dispatch group is something that we need now while doing this either we can wait for the execution of all the operations of all the tasks to be completed and then proceed with our work or maybe we can continue with whatever we were doing and can get notified when the execution of all the task has completed so for achieving this dispatch groups provides us four important functions that is entirely wait and notify so the idea is that we create an object of dispatch group we call the enter function on that object whenever a task is added to the dispatch group whenever the execution completes we call the function leave and when the count of enter is balanced against the count of leaves that is when the execution of all of them is finished notify gets called so notify is called by the system where you get the Callback that the execution of all the tasks that you entered in the dispatch group is completed while you can also wait for the task to be finished and do not proceed with whatever you are doing using the weight function so let's see all this theory in action let's move to xcode so for understanding dispatch group and how they work the entirely weight notify and these functions let's take the example that I talked about earlier that is from the splash screen I want to make multiple API calls and want to proceed to the home screen only when I get the the success or maybe the response of all of them it can be either failure it can be success but only when the response is received for all the API calls we should proceed to the home screen now this is the example that I love when it comes to explain dispatch Pro it is the perfect candidate for it so let's see that what is happening here I'll walk you through the code and we'll put the link of the GitHub repo in the description so later if you want to clone it you can do it from there so in this Splash view controller the first thing that I'm having is activity indicator that is only for giving the feedback to the user that an an API call is in progress next I'm having a set of cancelables that is because I am using combine for making the the network calls and all those so if you're not comfortable with combine and want to get started with it here's the link of one of my videos that I did on combine so this is the setup and syllabus this is not related to dispatch group in any way and then we are having a dispatch group an object of the dispatch group that is launch data dispatcher we'll see it in a minute from the viewed load I am calling this method that is get app launch data from this method that is get app launch data I am making two API calls asynchronously that is one for user preferences and the second one for getting the app config and the end goal is that we should proceed to the home screen only when we get the response of both of them one way to do is to make the API call serial what I mean by serial is to make the second API call after getting the response of the first so that way we will move to the home screen only when we'll get the response of both of them but that will make the user weight on the slash screen needlessly because the response of both of these apis are not dependent on each other and we can make the API calls asynchronously we can call call both of them together so no need of making the user wait on the slash screen no need to hamper the user experience let's call them asynchronously and let's see that how dispatch group helps here so before calling this function get data which is responsible for the API call I am calling the enter function on the dispatch group object that we created this dispatch group object I am calling the enter function which tells the system that one task has entered the dispatch group increase the counter variable by 1 and whenever the leave will be called just reduce the counter variable so whenever the enter will be balanced against the leaves then notify the Callback function will be called so I call this function enter Then I made the API call before making another EPA call for app config I again called the enter function and in the Callback of this get data method that is the sync block I am calling the leave function here which means that the task that was entered in the dispatched group its execution is finished now you see that I am calling the leave function outside this completion block I mean outside the failure and the Finish block so regardless of the API Converse was success or it was a failure the response has been received the API call has completed so that is why I am calling the leave function outside this switch of completion same is being done here in the get data function which was called for the app config API again before switching on the completion I am calling the leave method here so it is very very important to balance the enter versus leave otherwise it leads to crash when number of leaves will be balanced against number of enters it means that there's no pending execution whatever tasks that were entered in the dispatch group execution of all of them has finished at that point of time the notify function will be called so in the notify function we are stopping the animation of the activity indicator and then navigating to the next screen whatever it can be so let me just give it a run and let's see this in action we see that API calls are taking time and here's the response so the base URL that is from the app config watch list that is from the user preferences and there was a print statement in the notify blog which was launch calls complete navigate to next screen we see that this statement got printed after these two statements that is base URL one and the watch list one which were in the get data function in the in the receive value block of the get data function which means that only after these two calls were completed the notify was called and that was the sole purpose of using dispatch group so it is that easy to use dispatch group just called the enter function whenever you enter a task and then leave whenever the execution is completed when both of them will get balanced each other notify will be called so this was one of the use cases now imagine that you are making two APA calls from from your splash screen and one of them which is which is not very critical it is taking let's say five seconds six seconds or maybe 10 seconds in that case you do not want your user to wait on the splash screen for that duration because the response of that API is not that critical you can proceed with the flow without even getting the response of that that particular one so the use case is like it is good to have the response of that API so let's just call it on Splash asynchronously but even if you do not get the response in maybe let's say two seconds or three seconds let's not wait for it and proceed with the flow so this is the requirement given to you by the product team now you would be thinking that we can use the async after function and can pass the time as maybe three seconds or four seconds whatever is the requirement so regardless of the completion of these API calls we will move to the next screen but what if I say that I want to know that whether the API calls were completed or not in that case the async after function won't help you so to deal with this situation there's another function provided by Dispatch group that is weight weight is basically used when we want to stop the execution happening on the current thread and proceed only when the tasks entered in the dispatch groups have finished their execution now because weight holds the execution it stops the execution happening on the current thread it should be never called on the main thread just make sure that whenever you use the weight function ideally you should not notify takes care of most of the situations but just in the scenarios like this one if you use weight just make sure that you do not use it on the main thread so let's see that how weight works instead of this notify let's just call wait here so at this line the execution happening on the current thread will stop and will proceed only when the execution of the dispatch group items is completed so let's do one thing here so I'm doing the same thing but without using notify once the weight will be completed we'll move to next screen let's give it a run the same thing happened we got the response of both the apis and after that this async block was executed so essentially after getting the response of both the apis the the animation of the activity indicator was stopped and we moved to the next screen so till this point we have not achieved what we talked about that do not wait for more than three seconds and even after three seconds if you move to the next screen I want to know that whether the call was successful or not now let's see that so first of all let me increase the response time of one of the apis so here in my network manager where I am having the URLs let me change the time to instead of four seconds let me make it say 7 Seconds and let me give it a run so it is clear that the API is taking time and responding so the base URL when the first API gave the response immediately while the second one is taking time and after seven seconds we got the response from the second one and then we moved to the sign up screen the next screen that that is supposed to now let's see that how can we use the weight function of getting the information of whether the execution was completed or not so for that we will use dispatch timeout result it is something which is returned by the weight function so if I go here you see that we have another variation of the weight function which takes the timeout duration after which we should proceed with the task and in this case we get something which is known as dispatch timeout result and we can switch on this for identifying that whether the execution was completed or not so let's use it here let me insult dispatch timeout result is equal to launch dispatch group dot weight and for timeout let's say now Plus maybe three seconds now once we get the weight result we can we can switch on it so inside the same dispatch block the sync block so switch on weight result and if it was a success let's print that API calls completed before timeout let's say and if the apis have timed out let's say apis timed out now we don't need this print statement let's give it a run and let's see that how this works we see that we got the response of only one API before the timeout duration that was three seconds after which the API is timed out because the duration that we set that was three seconds so we move to the next screen that was because this block this asynchronous block in which this function was called navigate to sign up PC this was called immediately after three seconds we didn't wait for the apis to respond because the other API was taking seven seconds but we know that apis have timed out so even if we have moved to the next screen if you want to make the API call for getting the response at some later point of time we know that the API failed earlier because of the timeout so this is how we can get the callbacks when all the asynchronous tasks are done executing or if you want to wait for some particular duration we can use the different variations of the weight function for that we can also use the information received from the weight function for identifying that whether it was a timeout or it was a success so that was about the dispatch group and believe me it is very very useful so if you are not very comfortable with dispatch groups just try these things and get a hang of it let's move to dispatch work item so just like dispatch group dispatch work item is another one of the coolest stuff provided by gcd in interviews when I ask candidates that how comfortable they are with concurrency what do they prefer gcd or operation queue most of the candidates say that they prefer operation queues and as an answer to the why part of the question they say that because operation Q provides the feature like cancel by using operation queues we can cancel the tasks which are being executed or they are about to be executed so that is why they prefer operation queues well this is a misconception about gcd long back gcd added the support for canceling the task which have not executed yet using dispatch work item so through dispatch work item you basically encapsulate a block of code it becomes a work item and now this work item can be dispatched either to a dispatch group or maybe a dispatch queue and then you get the flexibility to cancel that particular work item basically the the block of code which was encapsulated in the dispatch work item you can cancel it unless its execution has started so this again becomes one of the very useful features because at times we want want to cancel the operation while they are being executed or they are about to be executed for example consider search you generally make an API call on every character entered in the search box now most of the times user is interested in the search result after he completes the typing so for example let's say I want to search about Johnny Depp I started typing j o h n y and you are making an API call on each of these connectors well I'm not actually interested in the results which I will be getting after J or j o or j o h i want the results which would come after j o h and y the suggestions the actual results they would be more relevant of the actual query that is Johnny so in this case maybe we can avoid the API cost made after j j o j o h so the question comes that how will we come to know if user has stopped typing or if he is actually interested in the results of joh or how will we cancel the calls which have been already executed or or how it is going to take place so we will have a look at that example that implementation in a minute but before that let's see that how cancel works so if you set the cancel property as true before the execution is started the execution won't take place basically you have canceled that operation if the work item is canceled during the execution the cancel property will return true so that the developer comes to know that the cancellation is actually requested and then they can take care of it but the execution won't be aborted by the system so that is something the developer needs to take care of and for getting the Callback the wait and notify function works the same way as we software the dispatch group so that was something important to understand about the cancellation of dispatch work item now let's look at the implementation of all this through the example that I was talking about let's move to xcode let's continue the same example that we were working on so from a splash screen we use dispatch group and we made the the API calls parallelly we'll end it up on the sign up screen now on this sign up screen I want the user to to select the username whatever they want to because they are they are just starting with the application so they are free to choose whatever username they want but at the same time I want to check the availability of that username so username should be unique and I don't want to show the error to the user after they hit sign up instead I want to tell user while they are typing while the user is typing in the username field we can make the API calls and based on the response we can tell if this username is available or not so this is exactly the same thing that happens with search so let's see that how can we use dispatch work item here to avoid the unnecessary API calls but at the same time to achieve what we want so here in this signup view controller again this is sign up label array label and the other UI stuff which are not related to dispatch work item so I'm just skipping and this is the function that is check username availability this is called from the delegate method of the text field that is should change characters in range so here whenever the change will happen in the text field I am calling this method check username availability and passing the string passing the text entered in the text field and then the API call will be made against that that string as the query text so in this function we are creating an object of a dispatch work item and wrapping this entire piece of code which is responsible for the API call in that particular work item so that it can be canceled so this is the function that is in my network layer for for making the API call about the username availability and this is wrapped inside this dispatch bug item that is work item also I am having a global variable here that is username availability work item so you will understand the purpose of taking this Global variable in a minute let's first go through the code so on the first line of this function I am calling the cancel function of this username availability work item the global variable that we are having then I'm making this work item that is dispatch work item and it is it is having the the code for making the API call after this I am assigning this local variable work item to This Global one and then we are adding a delay before the execution of that work item so that the unnecessary API calls can be avoided so here I have chosen the dispatch queue Global async after and now a delay of one second from now and then this work item will be executed so once this work item will be executed the API call will be made and then we will show the error if the username is not available so let's see that how it looks let's try writing something here say Patrick and now I got the error that this username is not available so you see that the API call was made only when I stopped writing that is after one second after I stopped writing so with each character this function is being called from the delegate method but at the very first line the existing work item is being canceled and as soon as I stopped writing after one second the last work item that was stored in This Global variable that is being executed so again if I try writing something I hit say Jane you see that I didn't get the error immediately so if I try say 0 8 there's a slight delay in the error and that is because the API call is being made after I am stopping the writing so 0 8 is not available 0 7 0 7 is also not available and I see that I made a typo here so if I correct this with Patrick Jane 0 is not available 0 7 is available we don't get the error here so this is just for this example but the point that I want to convey here is that how can we use the dispatch work items so for this example what I did is that I wrapped a block of code that was responsible for making an API call inside a dispatch work item executed the work item with a slight delay and this way we avoided unnecessary API calls so this is one of the use cases where you can use the dispatch work item but other than this you will actually find tons of use cases where you will feel like using dispatch work item and that would actually help in optimizing the code so that was pretty much about this video in the next video on this concurrency series we will see dispatch work item Flags to be specific dispatch barrier and dispatch Sim offers the dispatch source and everything that is remaining in GCB if you like my video use if you like the content you can consider subscribing to the channel next video will be available very soon till then Happy coding and stay safe
Info
Channel: iCode
Views: 14,018
Rating: undefined out of 5
Keywords: concurrency, ios, swift, gcd, grand central dispatch, icode, pallav, mobile, android, multithreading, parallelism, threads, data race, target queue, main thread, main queue, qos, quality of service, dispatch group, dispatch work item, cancelling task in gcd, dependency
Id: SGEWlYB6ZM0
Channel Id: undefined
Length: 20min 25sec (1225 seconds)
Published: Sat Jul 30 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.