CS333

Mobile Development


Ilya Loshkarev
loshkarev.i@gmail.com

Grand Central Dispatch

Concurrency & Parallelism

Parallelism and Concurrency

Queue Abstraction

GCD Queues

Dispatch Queue

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

Queue Type vs Dispatch Type

Queue

  • Concurrent - unordered
  • Serial - ordered

Dispatch

  • Async - no wait
  • Sync - wait

Quality of Service

System prioritizes and schedules queues
according to their QoS attribute

  1. User Interactive
  2. User Initiated
  3. Utility
  4. Background
  5. Default

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 TASK */
                  dispatch_async(dispatch_get_main_queue()) {
                    /* present results to the user */
                  }
                }
          

Depricated since iOS 10.0 👌

Calling for Dispatch Queues


              // Get some queue to put our task into
              DispatchQueue.global(qos: .qosUserInitiated).async {
                  /* do some heavy work */
                  DispatchQueue.main.async {
                      /* present results to the user */
                  }
              }
            

Creating Dispatch Queues


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

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

Operation Queue

Core Data Concurrency

Private Queue


              let privateMOC = NSManagedObjectContext(
                  concurrencyType: .PrivateQueueConcurrencyType)
              privateMOC.parentContext = context
            

Child context with its own private queue
allows to perform concurrent operations

Perform Block


            privateMOC.performBlock {
                for data in collection {
                    /* insert objects into the private context */
                }
                // save changes to parent context
                try! privateMOC.save()
                context.performBlockAndWait {
                    /* go to main queue to save changes */
                    try! context.save()
                }
            }
          

performBlock puts closure into context's queue of operations

Notifications

Observer Pattern

A software design pattern in which an object maintains a list of observers and notifies them automatically of any state changes
Observer Diagram

Notification Center

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

              let defaultCenter = NotificationCenter.default
            

Notification


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

An object distributed through Notification Center

Post


              defaultCenter.post(name: "MyNotification", object: self)
              defaultCenter.post(name: "MyNotificationWithPayload",
                  object: self,
                  userInfo: ["payload" : myPayload])
            

Any notification should have a unique name within an app

It is a good idea to store notification names in an enumeration

Observe


              defaultCenter.addObserver(self,
                  selector: #selector(myNotificationHandler),
                  name: "MyNotification", object: sender)
            

Calls self.myNotificationHandler
whenever MyNotification is posted


              defaultCenter.removeObserver(self,
                  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

Concurrency


              DispatchQueue.main.async {
                  defaultCenter.post(name: "MyNotification", object: nil,
                      userInfo: ["data":data])
              }
            

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

Core Data Notifications


              defaultCenter.addObserver(self,
                  selector: #selector(managedObjectContextObjectsDidChange),
                  name: NSManagedObjectContextObjectsDidChangeNotification,
                  object: context)
            

Managed Object Context has three types of notifications


              // NSManagedObjectContext ObjectsDidChange Notification
              // NSManagedObjectContext WillSave Notification
              // NSManagedObjectContext DidSave Notification
            

Context Did Change


              func managedObjectContextObjectsDidChange(notification: NSNotification) {
                  // userInfo holds information about the changes
                  guard let userInfo = notification.userInfo else { return }
                  if let inserts =
                      userInfo[NSInsertedObjectsKey] as? Set<NSManagedObject> {  }
                  if let updates =
                      userInfo[NSUpdatedObjectsKey] as? Set<NSManagedObject> {  }
                  if let deletes =
                      userInfo[NSDeletedObjectsKey] as? Set<NSManagedObject> {  }
              }
            

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