GCD

Threading Overview:

In general a thread execution is the a task performing by core processors , a task can be a function , a method , a  block or anything that require processor(s) to consume it!!!

As a Developer we have 4 options to use Threads:

1) pthreads (exposed by POSIX) 

2) NSthread (Apple SDK Object based on pthreads created in Objective-C  OSX>= 10.0 and iOS>=2.0)

3) GCD ( Threads C functions  OSX>= 10.7 and iOS>=4.3)

4) NSOperation, NSBlockOperation (OSX>= 10.5 and iOS>=4.0)

pthreads is a C syntax which managing lifecycle is up to you , rarely directly used 

NSthread :  Objective-C syntax managing lifecycle is up to you

Apple encourages developers to use approach 3 & 4 for threading , so we're going to focus on GCD and NSOperation classes family:

Both concept of GCD and NSOperation suit are based on Queuing : in both cases we have two steps in order to create and use Threads 1) create/obtain a Queue  2) submit our task(s) to Queue



NSXXXOperation

NSOperation is an abstract class and  not used directly , instead you can use NSBlockOperation , NSInvokeOperation,NSOperationQueue,... but they all rely on the same principal concept except detail differences and ofcourse the fact that NSBlockOperation,... are  following OOP pattern.

Example using NSBlockOperation :

 let queue = NSOperationQueue()
 let operation = NSBlockOperation(block:{()->Void in
  doCalcule()
//NO UI operation

})

queue.addOperation(readOperation) //start thread

In order to perform any UI operation kind of update ,reloading tableview….etc , you can use a Main Queue  and submit it inside your block after your calclculation is over like this

let queue = NSOperationQueue()
 let operation = NSBlockOperation(block:{()->Void in
  doCalcule() 
//NO UI operation

NSOperationQueue.mainQueue().addOperationWithBlock({()->Void in
self.mTableView.reloadData() })
//any UI operation here reloading a TableView

})

queue.addOperation(readOperation) //start thread


Other solution is to use completionBlock Other  closure which is a property of NSBlockOperation as shown here

 let queue = NSOperationQueue()

        let operation = NSBlockOperation(block: {()->Void in

             doCalcule() //NO UI operation

                   })

        operation.completionBlock = {

            let mainQueue = NSOperationQueue.mainQueue()

            let uiOperation = NSBlockOperation(block: {()->Void in

                self.mTableView.reloadData()

            })

            mainQueue.addOperation(uiOperation)

        }

        queue.addOperation(readOperation)

NSOperation and NSBlockOperation are the implementation of GCD in a higher level , GCD is written in C language and is considered as a low level implementation , so in term of OOP programming Apple implemented NSOperation and NSBlockOperation and in many operation it would be preferable to use them over GCD syntax threading



GCD: Grand central dispatch


Remind :

Similar to Android concept in IOS threads are divided to two categories Safe/Unsafe , UIKit components mostely are by deafult not safe, that means access UI elements from a Non-Main Threads are not allowed and raise exceptions.


GCD is designed to centralize all threads task management and threads manipulation by delegating it to system

this way developers are focusing on high level task preparing rather than low level thread manipulation which is a complex task when sync & concurrency come to game!

To use GCD first enqueue or ask for Queue (find lineup for request!) then give your instruction and wait!


1)dispatch_get_global_queue : For a Non-UI or global scoop routine

2)dispatch_get_main_queue: For a UI or Main scoop routine (executed in the context of your main thread of your Application)


example:

let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

dispatch_async(queue {

//non-UI Closure todo

};)



In fact the task codes we want to execute on a Thread are the closure we pass to Queue

An example for most commun scenario in this case is when updating your UI after some background operation done


let queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

dispatch_async(queue1 {

//non-UI Closure todo

};)


let queue2 = dispatch_get_main_queue();

dispatch_async(queue2 {

//UI Closure todo

};)


In a real world scenario there will be pereferable to organize your threads in a pool of threads called "Group"

To do that first create a dispatch group:

let group = dispatch_group_create()

then run threads as below


dispatch_group_async(group, 

queue1{ 

firstResult = self.firstCalculation(processedData)

})


dispatch_group_async(group, 

queue1{ 

firstResult = self.secondCalculation(processedData)

})


dispatch_group_notify(group, queue1) {

let results=xxxx //results

//update UI

dispatch_async(queue2 {

//UI Closure todo

};)



dispatch_group_notify : tell the group that if every threads in groups are done notify me!

so the following closure will be executed after all threads in queue are done!


dispatch_group_notify(group, queue) {

//closure body

}

=======================

Mac OS has a extrem safe mechanism for multithreading called GCD, and strongly recommend to not use Threads directly instead you submit your task to system and let him to manage your threads.

You submit it through Dispatch Queues (Queuing is First_In_First_Out)

A serial dispatch queue runs only one task at a time, waiting until that task is complete before dequeuing and starting a new one. By contrast, a concurrent dispatch queue starts as many tasks as it can without waiting for already started tasks to finish.


let qualityOfServiceClass = QOS_CLASS_BACKGROUND

let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)

dispatch_async(backgroundQueue, {

    println("This is run on the background queue")


   dispatch_async(dispatch_get_main_queue(), { () -> Void in

        println("This is run on the main queue, after the previous code in outer block")

    })

})

 © Xosrov 2016