神刀安全网

Introduction to Grand Central Dispatch in Swift

In thisSwift Tutorial I am going to cover a topic that many new comers toSwift Programming seem to dread: Grand Central Dispatch (GCD). I will hopefully settle your fears to what GCD is and show you how to implement GCD in Swift.

Jump To:

What is GCD?

This is what the Apple website has to say:

Grand Central Dispatch (GCD) comprises language features, runtime libraries, and system enhancements that provide systemic, comprehensive improvements to the support for concurrent code execution on multicore hardware in iOS and OS X.

And true to Apples’ reputation, This does not explain simple to ‘noobs’. Basically, GCD allows you to multitask using threads (Multithreading).

Basics of Threading

It is very common throughout programming to hear the term threading. Threads contain processes and each thread runs concurrently. When you only have one core the system will switch between the threads that are currently executing. If there is more than one core then the threads will be distributed between them for processing.

On of the main concerns with threading is making sure things are thread safe. I will discuss this concept a little later within this Grand Central Dispatch Tutorial.

By default most of your iOS program will run in the main thread and thus you do not have to worry about anything. You can however create unique threads so that you can allocate processes to run differently.

This allows the app to multitask without getting caught up one thing at a time. You will see in this GCD tutorial one way of handling that.

Why use GCD?

One of the biggest challenges today for developers is the ability to keep your app responsive in response to users, the bigger your app gets, the more functions and functionality you add the slower it gets and subsequently the less user friendly your app becomes. Well not anymore.

You can use GCD to run your app threads and present information to the user. For example, let’s say that you want toParse JSON in Swift, the JSON file is very large and this is going to take 10 seconds. (Wait, only 10 seconds, that does not seem long. Trust me to a user, that is a lifetime). What you can do with GCD is to display an activity indicator to the user. You will have seen these little loading symbols everywhere. Just Google Throbber and you will see straight away what I mean.

I would personally recommend always using Grand Central Dispatch when you have to connect to any external resource.

As technology improves, the hardware gets better and now, in a lot of cases devices have multiple CPUs. When you use GCD you can split your processes up into small manageable chunks, distribute them between threads and even onto different CPUs allowing you to provide a faster more efficient app to the user.

TL;DR GCD Example

For those of you who just skipped the above information and just wan to get into coding, then start from here.

So now I am going to show you how to create an app that uses Grand Central Dispatch in Swift. For this I have created a basic demo application that does not use GCD We are going to build on this. Download the Demo files

Download the project, run the app and click the button that says get results. You will notice that the app appears to freeze up and looks like it is not doing anything. Then after 20 seconds you will see an output in the console and the button becomes clickable again.

You see the problem with this?

Ok, Let me explain what the demo project is doing. In the ViewController.Swift file you will see this function:

 func simulateServerRequest() -> String {     NSThread.sleepForTimeInterval(20)     return "This is the Result" } 

This function is what will be replaced by your REST API call to the server. For the purpose of this project I have just added in this line:

 NSThread.sleepForTimeInterval(20) 

It looks pretty self explanatory: This will pause the execution of the code for 20 seconds which will simulate a slow response form the server and thus highlighting the need to use Grand Central Dispatch.

We then have an IBAction which will trigger when we click a button and run the above code.

dispatch_queue_priority_default()

So, we can make our function simulateServerRequest() run in the background by wrapping it in a a GCD closure called: dispatch_async which will assign it to a queue.

Get the demo project and go to the ViewController.Swift file. The first thing we are going to do is access a global queue that is always available using dispatch_get_global_queue . Find the IBAction code (This is where we are going to do our work. The code that is already there looks like:

 @IBAction func getResultsButton(sender: AnyObject) {     print(simulateServerRequest()) } 

Let us make an instance of dispatch_get_global_queue() and assign this to a variable called gcdQueue . dispatch_get_global_queue() takes two arguments: The first one will set the priority and the second is currently to be unused so it should always be 0 .

 let gcdQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) 

Now we can call the dispatch_async function and pass in the variable as a parameter:

 dispatch_async(gcdQueue) {    // This is where we add our functionality } 

You will now get this error:

Call to method ‘simulateServerRequest’ in closure requires explicit ‘self.’ to make capture semantics explicit

We just need to add self. to our function:

 print(self.simulateServerRequest()) 

Run the app. You can see now that the button no longer looks frozen and if you wait the allotted time the function still runs. This is where you would present some feedback to the user, We will get to this later in the tutorial.

UIKit Thread Safety

Ok, so you have a project that utilises background threads with Grand Central Dispatch. Fantastic. However, that is all it does. What happens when you want to change any of the UI Elements? Let’s try it.

On the Main.Storyboard drag on a label and link it up to an IBOutlet in your code:

 @IBOutlet weak var labelVC: UILabel! 

Now, in your function, make the label update when the function is complete:

  func simulateServerRequest() -> String {         NSThread.sleepForTimeInterval(5)         self.labelVC.text = "success"         return "This is the Result"     } 

Run the app. Nothing happens right? This is because of UIKit Thread Safety. A note from Apple:

For the most part, UIKit classes should be used only from an application’s main thread. This is particularly true for classes derived from UIResponder or that involve manipulating your application’s user interface in any way.

Luckily Grand Central Dispatch has a method for this: dispatch_get_main_queue() . Now, in our function we would call it by wrapping self.labelVC.text = “success” like so:

 func simulateServerRequest() -> String {     NSThread.sleepForTimeInterval(5)     dispatch_async(dispatch_get_main_queue()) {         self.labelVC.text = "success"     }     return "This is the Result" } 

Run the app again. Now the label will update with “Success”.

User Feedback

Now we are going to display an activity indicator to the user. For this example I am going to use the beautiful Swift Spinner . Copy that SwiftSpinner.Swift file into your project.

For a quick example of how this lovely Activity Indicator works, add the following into your viewDidAppear function (You might need to create this function):

 override func viewDidAppear(animated: Bool) {     SwiftSpinner.show("I am pretty!") } 

So now you have seen how well it looks, let’s implement it. In our function, lets add:

 SwiftSpinner.show("I am pretty!") 

Here is the full function:

 func simulateServerRequest() -> String {     SwiftSpinner.show("Processing..")      NSThread.sleepForTimeInterval(5)      dispatch_async(dispatch_get_main_queue()) {         self.labelVC.text = "success"     }     return "This is the Result" } 

If you run the app now, you will get the following error

GrandCentralDispatch_Project[43306:974317] This application is modifying the autolayout engine from a background thread, which can lead to engine corruption and weird crashes. This will cause an exception in a future release.

This is because of the theI mentioned earlier, if you remember. That is ok however, we do have a solution, the same Grand Central Dispatch. So again, lets wrap it like so:

 dispatch_async(dispatch_get_main_queue()) {     SwiftSpinner.show("Processing..") } 

Run you app again and click the button. It looks fantastic right? wait.. Why is it not disappearing after the time has elapsed? We now need to tell it to hide using .hide() . Here is the full function so you can see:

 func simulateServerRequest() -> String {      dispatch_async(dispatch_get_main_queue()) {          SwiftSpinner.show("Processing..")     }              NSThread.sleepForTimeInterval(5)              dispatch_async(dispatch_get_main_queue()) {          self.labelVC.text = "success"          SwiftSpinner.hide()     }     return "This is the Result" } 

Download

You can skip all this and go straight to the code if you want. Please help us out by using one of the social media buttons below and we will be happy to give you the files.

Summary

In this Swift Grand Central Dispatch Tutorial I have succinctly covered iOS Threading and thread safety. Then I showed you how to pass a process to run on a different thread, the background allowing you to free up the app and present a better user interface.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Introduction to Grand Central Dispatch in Swift

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
分享按钮