Mobile Development

Ilya Loshkarev

Grand Central Dispatch

Concurrency & Parallelism

Parallelism and Concurrency

Queue Abstraction

GCD Queues

Dispatch Queues

Dispatch Queues are objects that maintain a queue of tasks and execute these tasks
in their turn

Queue Type vs Task Type

Queue concurrent unordered
serial ordered
Task async non blocking
sync blocking

Ghost of the Syntax Past

						// Get some queue to put our task into
						dispatch_async( dispatch_get_global_queue(
							Int(QOS_CLASS_USER_INITIATED.rawValue), 0) )
							/* do some heavy work */
							dispatch_async(dispatch_get_main_queue()) {
								/* present results to the user */

Depricated since iOS 10.0 đź‘Ś

Dispatch Queues since Swift 3

						// Get some queue to put our task into .userInitiated).async {
							/* do some task */
							DispatchQueue.main.async {
								/* present results to the user */

Any UI operation should be performed on the main queue

Quality of Service

					.userInteractive  // highest priority
					.utility          // default
					.background       // lowest priority

System prioritizes and schedules queues
according to their QoS attribute

Creating Dispatch Queues

						let backgroundQueue = DispatchQueue(label: "",
								qos: .background,
								attributes: .concurrent)

						backgroundQueue.async {
							print("Dispatched to background queue")

Created queue can be accessed by label

Dispatch Groups

							let group = DispatchGroup() group){
								/* do stuff */
							group.wait() // wait for every task in group to complete

							group.notify(queue: DispatchQueue.main) {
								/* do this after every task in the group is completed */

Allow to perform barrier based synchronisation

Dispatch Semaphores

							let semaphore = DispatchSemaphore(value: 10)
								/* access some shared data */

Implementation of a traditional counting semaphore

Operation Queues


						// Performs the receiver’s non-concurrent task
						func main()
						// The block to execute after the operation’s main task is completed
						var completionBlock: (() -> Void)?

An abstract class you use to encapsulate the code and data associated with a single task

Operation Queue

							let q = OperationQueue()
							q.qualityOfService = .utility
							q.maxConcurrentOperationCount = 10
							q.isSuspended = true
							let op = BlockOperation { /* do stuff */ }
							op.completionHandler = { /* do other stuff */}
							q.addOperation(op: op)
							q.isSuspended = false

Operation Priority & Dependencies

							let op = BlockOperation { /* do stuff */ }
							op.queuePriority = .high
							let dependentOp = BlockOperation { /* do other stuff */ }
							dependantOP.addDependency(op) // requires 'op' to be completed

Operation Queue schedules operations according to their dependencies and priority

Operation Status

							var isCancelled: Bool
							var isReady: Bool
							var isExecuting: Bool
							var isFinished: Bool
							var isConcurrent: Bool

Subclassing Operation

							class FileringOperation: Operation {
								var filter: CIFilter!
								weak var imageView: UIImageView?
								var result: UIImage?

								func main() {
									if isCanceled { return }
									if let source = imageView?.image {
										result = filter.apply(to: source)

Key-Value Coding


Key-value coding is a mechanism that allows objects to provide indirect access to their properties

							// Returns the value for the property identified by a given key
							func value(forKey key: String) -> Any?
							// Sets the property of the receiver specified by a given key to a given value
							func setValue(_ value: Any?, forKey key: String)

Adopting KVC

							class KVCPerson: NSObject {
								@objc var name: String = ""
							var kvc = KVCPerson()
							kvc.setValue("I'm a KVC Object", forKey: #keyPath(

There is no explicit KVC protocol, but any subclass of NSObject is KVC compliant

KeyPaths in Swift 4

							class Person {
								var name: String
								var bestFriend: Person? = nil
							var han = Person(name: "Han Solo")
							var luke = Person(name: "Luke Skywalker")
							luke.bestFriend = han

							luke[keyPath: \] = "Master Luke"
							luke[keyPath: \Person.bestFriend?.name]  // "Han Solo"

Dedicated KeyPath type allows to reference properties

Works with any Swift type
Would support subscripts in the future

Key-Value Observers

Key-value observing is a mechanism that allows objects to be notified of changes to specified properties of other objects

							func observeValue(forKeyPath keyPath: String?, of object: Any?,
								change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)

							func addObserver(_ observer: NSObject, forKeyPath keyPath: String,
								options: NSKeyValueObservingOptions = [], context: UnsafeMutableRawPointer?)
							func removeObserver(_ observer: NSObject, forKeyPath keyPath: String)

Responsible Observation

							class MyObserver: NSObject {
								var myContext = 88888888
								override init() {
												forKeyPath: #keyPath(Observed.propertyName),
												options: .new, context: &myContext)
								deinit {
												forKeyPath: #keyPath(Observed.propertyName),
												context: &myContext)

Responding to KeyValue Changes

							override func observeValue(forKeyPath keyPath: String?, of object: Any?,
									change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
								if context == &myContext {
									if let newValue = change?[.newKey] {
										print("Value changed: \(newValue)")
								} else {
									super.observeValue(forKeyPath: keyPath, of: object,
										change: change, context: context)

Considered Harmful!

  • Comes through one method
  • Requires you to handle superclasses yourself
  • Obscures control flow
  • Can crash while deregistering

Property Observers

							class Person {
								var name: String {
									willSet {
										print("name will be set to \(newValue)")
									didSet {
										print("name has been changed from \(oldValue)")


Notification Center

Provides a mechanism for broadcasting information within a program
Notification Center Diagram

						let defaultCenter = NotificationCenter.default


						  name: String // unique name
						  object: AnyObject? // sender
						  userInfo: [:]? // additional data

An object distributed through Notification Centers

Custom Notifications

							extension Notification.Name {
								static let myNotification = Notification.Name("MyNotification")
								static let myNotificationWithPayload = Notification.Name("MyNotificationWithPayload")

Any notification should have an unique name within the app

All default notification names are stored in
Notification.Name class

Send Notification .myNotification, object: self) .myNotificationWithPayload,
							object: self,
							userInfo: ["payload" : myPayload])


								selector: #selector(myNotificationHandler),
								name: "MyNotification", object: sender)

Calls self.myNotificationHandler
whenever MyNotification is posted

								name: "MyNotification", object: sender)

Observers should be removed manually on deinit

Observe with Block

						defaultCenter.addObserver(forName: "MyNotification",
							object: sender, queue: nil) {
								[weak self] notification in
								/* handle notification */

Performs closure in specified queue

Strong references to self in closures
can create reference cycles


						DispatchQueue.main.async { "MyNotification", object: nil,
								userInfo: ["data":data])

Notification centers deliver notifications on the thread
in which the notification was posted

Considered Harmful?

  • Notifications make it harder to trace the flow of control
  • Deinitialized observers crash the app
  • Notification centers are not well suited for unit tests

Related Resources