GCD and Delay calls
Posted by Wang Wei (@ONEVCAT) on 2015/05/13
The sample code in this section needs to be run in the Xcode project environment because Playground cannot be dispatched in a thread without special configuration. The correct results may not be available in the Playground.
GCD is a very convenient way to use multithreading. By using GCD, we can make flexible multithreaded programming in the context of ensuring that the syntax is as simple as possible. In multithreaded programming of "complex must die", keeping simple is the golden rule of avoiding mistakes. The good news is that the GCD API can be used seamlessly in Swift, and thanks to the inclusion of closure features, it is easier to use than before in Objective-c. I'm not going to spend a lot of time here to introduce GCD's grammar and elements, and if you do, you can write a section specifically for GCD. In the following I give an example of the most commonly used in daily life (saying this example can cover more than 50% of the daily GCD use), to show what the GCD call in Swift would look like:
//Create destination queue let workingqueue = Dispatch_queue_create ( "My_queue", nil) //distributed to the queue that was just created, GCD will be responsible for thread scheduling Dispatch_async (workingqueue) {// Asynchronously println in Workingqueue ( "hard work") nsthread.sleepfortimeinterval (2) / /Analog two-second execution time Dispatch_async (Dispatch_get_main_queue ()) {//return to the main thread update UI println (" end work, update UI ")}}
Because UIKit
it can only work in the main thread, if we do heavy work on the main thread, it will lead to the app "stuck" phenomenon: UI can not be updated, user input is not responding, etc., is a very bad user experience. To avoid this, we should put them in a background thread for the heavy lifting (like adding filters, etc.) or it will take a long time to complete (such as downloading pictures from the web), so that the UI can interact with the user and there will be no Dayton. After the work is done, we need to update the UI and we have to go back to the main thread (keeping in mind that the UI-related work needs to be performed on the main thread, otherwise unpredictable errors can occur).
In the daily development work, we often encounter such a requirement: after xx seconds to execute a method. For example, the switch interface 2 seconds after the start of an animation, or the prompt box appears 3 seconds after the automatic disappearance and so on. Previously in objective-c, we could use an NSObject
instance method to specify that -performSelector:withObject:afterDelay:
a selector be executed after a certain number of times. However, if you create a new Swift project now and try to use this method (or all the other variants of this method), you will find that this method is gone!
What happened? Because we have emphasized many times, Swift's big pursuit is the security two words, but originally performSelector:
this set of things under ARC is not safe. Because ARC is used to ensure that the parameters are present during the operation of the method, the input parameters are retain at the beginning of the method and then in the final release. For performSelector:
This method we do not have the opportunity to specify parameters for the called method, so the input of the called selector may be pointing to the unknown garbage memory address, and then ... HOHO, the hell is this kind of collapse can not be repeated every time, go to hell.
But what if we still want to do the deferred call anyway? The easiest thing to think about is a timer that is used NSTimer
to create a call once a few seconds later. But in doing so, we need to create a new object that is related to an inherently unrelated NSTimer
class, and also uses the OBJECTIVE-C runtime feature to find methods and so on, which is always a bit cumbersome. In fact, there is a very useful delay call in GCD we can use to write a very beautiful method, that is dispatch_after
. The simplest way to use it looks like this:
let time: NSTimeInterval = 2.0let delay = dispatch_time(DISPATCH_TIME_NOW, Int64(time * Double(NSEC_PER_SEC)))dispatch_after(delay, dispatch_get_main_queue()) { println("2 秒后输出")}
The code is very simple, and nothing worth detailing. Just write so much each time is also very tired, here we can slightly package it to use some of the best, plus the cancellation function. Because GCD has evolved amazingly in IOS 8 and now has a feature that stores a block dispatch_block_t
, we can easily cancel one that is waiting to be executed block
. Cancel a task such a feature, which was previously a NSOperation
patent, but now we can use GCD to achieve the same goal. The entire package may be a bit long, but it's worth reading. It can also be used as a practice material to test your Swift basic Grammar mastery:
ImportFoundationTypealiasTask = (Cancel:Bool) ()Func Delay (Time:Nstimeinterval, Task: (), ())Task? {Func Dispatch_later (Block: ()) {Dispatch_after (Dispatch_time (Dispatch_time_now,Int64 (Time *Double (NSEC_PER_SEC))), Dispatch_get_main_queue (), Block)}var closure:dispatch_block_t? = Taskvar result:task? let delayedclosure: task = {cancel in if let internalclosure = closure { if (cancel = = false) {Dispatch_async (Dispatch_get_main_queue (), internalclosure);}} Closure = nil result = nil} result = Delayedclosure Dispatch_ Later {if let delayedclosure = result {delayedclosure (cancel: Span class= "hljs-built_in" >false)}} return result; func Cancel (task:task?) {task?} (Cancel: true)}
It's easy to use and we want to do something after 2 seconds:
delay(2) { println("2 秒后输出") }
If you want to cancel, we can leave a Task
reference to the pair first, and then call cancel
:
let task = delay(5) { println("拨打 110") }// 仔细想一想..// 还是取消为妙..cancel(task)
GCD and Delay calls