Utilizing GCD in IOS Application Development

GCD?

  • An Acronym for Grand Central Dispatch
  • Multi-tasking in multi-core -> paralell
  • Multi-tasking in a single-core -> concurrent
  • 2 ways to do Multi-tasking in IOS -> NSOperationQueue / GCD
  • GCD handles difficulties without taking complex problems into account.
  • queue: a bunch of code. FIFO
  • work item: a block of code, can be reused. execution in a queue follows FIFO
  • View, Core Animation, and other UIKit classes -> main thread
  • Lengthy tasks -> background thread asynchronously
  • At launch time -> no additional work on main thread

GCD Usage

Sync vs Async

Sync : Sync with Main Thread. Main thread waits till the work item on the background queue finishes its work.

Async : Async with Main Thread. Main thread does not wait and finishes first (because it always have higher priority than others)


class ViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		syncTest()
	}


func syncTest(){
	let queue = DispatchQueue(label:"syncTestQueue")
	queue.sync {
	// change this to queue.async and see what happens
	for i in 0..<10{
	print("background", i)
	}
	}
	for i in 100..<110{
	print("main", i)
	}
	
}

}

QoS

  • QoS, Quality of Service, decides the queue’s priority
  • a task that has higher priority than others finishes earlier.
  • (prioirity order,) userInteractive > userInitiated > default > utility > background > unspecified
class ViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		qosTest()
	}


func qosTest(){
	let queue1 = DispatchQueue(label:"qosTestQueue1", qos: DispatchQos.userInitiated)
	let queue2 = DispatchQueue(label:"qosTestQueue2", qos: DispatchQos.utility)
	
	queue1.async {
	for i in 0..<10{
	print("userInitiated", i)
	}
	}
	
	queue2.async {	
	for i in 100..<110{
	print("utility", i)
	}
	}
	
}

}

Concurrent Queues

  • a queue that has more than one work item, it can execute items in either concurrent or serial(by default).
class ViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		concTest()
	}


func concTest(){
	let queue = DispatchQueue(label:"concTestQueue", qos: DispatchQos.userInitiated, attributes: .concurrent)
		
	queue.async {
	for i in 0..<10{
	print("work item 1", i)
	}
	}
	
	queue.async {	
	for i in 100..<110{
	print("work item 2", i)
	}
	}
	
}

}

Initially inactive Queus

  • a queue that is not active until the user activates the queue.
class ViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		initInactTest()
		if let queue = initInactQueue{
			queue.activate()
		}
		
	}

var initInactQueue:DispatchQueue!

func initInactTest(){
	let queue = DispatchQueue(label:"initInactTestQueue", qos: DispatchQos.userInitiated, attributes: .initiallyInactive)
	// since this queue is not activated until function initInactTest exits, 
	// we need to use class property to get the queue.
	
	initInactQueue = queue 
	
	queue.async {
	for i in 0..<10{
	print("work item 1", i)
	}
	}
	
	queue.async {	
	for i in 100..<110{
	print("work item 2", i)
	}
	}
	
}

}

Queue with delay

class ViewController: UIViewController {
	override func viewDidLoad() {
		super.viewDidLoad()
		queueWithDelayTest()

		}
		
	}



func queueWithDelayTest(){
	queue = DispatchQueue(label:"queueWithDelayTest", qos:.userInitiated)
	print(Date())
	let timeInterval: DispatchTimeInterval = .seconds(2)
	queue.asyncAfter(deadline: .now() + timeInterval){
	//timeInterval can be a double
	print(Date())
	}
	
	
	
}

}

Main and Global Queues

  • Main queue : Running for UI
  • Global Queues : Background queues
let globalQueue = DispatchQueue.global()

	globalQueue.async {
	for i in 0..<10{
	print("global queue 1", i)
	}
	}

  • Accessing Main queue from any other queue
DispatchQueue.main.async {
    
}

Work Item

  • work item: a block of code

func useWorkItem() {
    var value = 10
 
    let workItem = DispatchWorkItem {
        value += 5
    }
 
    workItem.perform() // performed in the main thread
 
    let queue = DispatchQueue.global(qos: .utility)
 
    queue.async(execute: workItem) // performed in the background queue
 
    workItem.notify(queue: DispatchQueue.main) {
        print("value = ", value) //invoked when 
    }
}

modified resources from: https://www.appcoda.com/grand-central-dispatch/

Written on January 27, 2018