SlideShare a Scribd company logo
Grand Central Dispatch
Design Patterns
By Robert Brown
@robby_brown
Blocks
Blocks

Blocks are a proposed addition to C.
Like a function pointer, except it also stores the context
the block was created in.
Similar to closures, lambdas, and anonymous functions
in other languages.
Blocks
Declaration Syntax:
returnType (^blockName) (Arguments)
Blocks may be anonymous.
Definition Syntax:
^ returnType (Arguments) { code; }
The return type and arguments are optional.
GCD provides function pointer variants to the block APIs.
Blocks
Blocks can modify local variables outside of their scope
if the variables have the new __block keyword.
Global and static variables can be modified without the
__block keyword.
Blocks automatically retain Objective-C objects, except
objects that use the __block modifier.
C objects must be manually retained.
Beware of retain cycles.
Grand Central Dispatch
What is GCD?

GCD is a lightweight multithreading engine.
Uses a thread pool.
Developers create queues of blocks rather than
threads.
Uses lock-less exclusion rather than mutual exclusion.
Replaces blocking and polling APIs.
Why Multithread on a Single
Core?

Keeps the UI responsive.
UI code runs on the main thread.
Everything else runs on a background thread.
Prevents the main thread from blocking or waiting.
Frequently Used APIs
dispatch_async(queue, block);
dispatch_once(token, block);
dispatch_queue_create(name, type);
dispatch_set_target_queue(object, queue);
dispatch_get_global_queue(priority, flags);
dispatch_release(object);
Global Queues

Four global queues:
  Main, Low, Default, and High.
Only the main thread services the main queue.
The three other queues determine the priority of
background tasks.
Enqueuing is thread safe.
Design Patterns
What is a Design Pattern?


After working on related problems, patterns often
appear in the solutions.
Formalized description of best practice.
Initialization Pattern
dispatch_once

Guaranteed to run only once for the lifetime of the
application.
Fast and thread safe.
Very easy to use.
Great for singletons and static class variables.
The Old Way
static MyObject * myObject = nil;
+ myObject {
    @synchronized(self) {
        if (!myObject) myObject = [MyObject new];
    }
    return myObject;
}
Problems With
@synchronized
@synchronized is slow.
When synchronizing on the class instance, all
other methods that synchronize on it will
temporarily block incoming messages.
You can’t synchronize on the class variable since it
is initially nil.
Using a custom lock also faces the initialization
problem.
The GCD Way
static MyObject * myObject = nil;
+ myObject {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
          if (!myObject) myObject = [MyObject new];
    });
    return myObject;
}
Lockless Exclusion Pattern
Mutual Exclusion

Mutual exclusion is classically handled by semaphores
or locks.
Both are most efficient when there is no sharing
conflicts, (i.e. when you don’t need them) and don’t
scale well.
Queues are efficient and scale very well.
In fact, queues are most efficient under high conflict.
Thread-safe Access
// myQueue must be a serial queue      NSLock * lock = [NSLock new];



dispatch_async(myQueue, ^{             [lock lock];

      [self setMySharedVariable:42];   [self setMySharedVariable:42];

});                                    [lock unlock];
Enforcing Lockless
Exclusion

- (NSInteger)mySharedVariable {
     NSAssert(dispatch_get_current_queue() ==
     myQueue, @“Wrong queue.”);
     return mySharedVariable;
 }
Problems with Getters/
Setters

We would rather have the compiler write our getters/
setters.
  This technique works well in other methods.
Only immutable objects are fully protected this way.
Enforcing Lockless
Exclusion
- (void)accessSharedVariableAsync:(void(^)(id sharedVariable))block {

     // myQueue must be a serial queue!

     dispatch_async(myQueue, ^{

           block([self sharedVariable]);

     });

}
Enforcing Lockless
Exclusion
- (void)accessSharedVariableSyncSafe:(void(^)(id sharedVariable))block {
     // myQueue must be a serial queue!
     if (dispatch_get_current_queue() == myQueue)
        block([self sharedVariable]);
     else
        dispatch_sync(myQueue, ^{
              block([self sharedVariable]);
        });
}
Compare to
      @synchronized
[obj accessSharedDataAsync:^(id sharedVar)   @synchronized ([obj sharedVar])

{                                            {

      // Critical code here.                       // Critical code here.

}                                            }

    Fast - No Locks                              Slow - Recursive Lock

    Allows private access                        Must allow public access

    Synchronous or Asynchronous                  Synchronous Only

    Can be extended to access many shared        Only single-value access.
    data values at once.
Striding Pattern
Why Striding?

  Myth: My app will go faster if I multithread.
  Your app will only be faster if the work is
  parallelizable.
  Sometimes a block simply contains a loop, and
  each iteration can be run independently of the
  others.
  So, why not spread the iterations across many
  threads?
One Thread

dispatch_async(myQueue, ^{
      for(int i = 0; i < 10; i++)
        [self doIndependentTask:i];
});
dispatch_apply

// myQueue must be a concurrent queue!
dispatch_apply(10, myQueue, ^(size_t idx) {
      [self doIndependentTask:idx];
});
Problems with
dispatch_apply
One thread per iteration may be overkill and result in
high overhead costs.
Solution: Use striding (i.e. have one thread run many
iterations).
  Similar to loop unrolling.
  You may need to profile your app to find the ideal
  stride length.
size_t stride = 4;

size_t iterations = 10;

size_t strideCount = iterations / stride;

// myQueue must be a concurrent queue!

dispatch_apply(strideCount, myQueue, ^(size_t idx) {

       size_t i = idx * stride;

       size_t stop = i + stride;

       do {

              [self doIndependentTask:i++];

       } while (i < stop);

});

// Pick up any left over iterations.

for (size_t i = strideCount - (strideCount % stride); i < iterations; i++)

       [self doIndependentTask:i];
Continuation Pattern
What is a Continuation?


Well, it’s complicated...take CS 330.
Think of it like a completion block wrapped in a
completion block wrapped in a completion block...
Using Continuations
The following steps are optional, but either 4 or 5 must be
done.
 1. Do some processing.
 2. Wrap the completion block in another block.
 3. Copy the block if it is going to cross threads
    (unnecessary with ARC).
 4. Pass the completion block to someone else.
 5. Execute the completion block.
typedef void(^CHCompletion)(NSError * error);

- (void)uploadPhoto:(NSString *)photoPath {

     // Do some pre-processing.

     [self processPhotoAtPath:photoPath completion:^(NSError * error) {

           if (error)

               dispatch_async(dispatch_get_main_queue(), ^{

                     // Inform user of error

               });

     }];

}
- (void)processPhotoAtPath:(NSString *)path completion:
(CHCompletion)completion {

     [[completion copy] autorelease];

     // Do some resizing and add a caption, then save the modified photo
     to a temporary file for memory efficiency.

     [self uploadProcessedPhotoAtPath:newPath completion:^(NSError *
     error) {

           // Delete the temporary file.

           if (completion) completion(error);

     }];

}
- (void)uploadProcessedPhotoAtPath:(NSString *)path
completion:(CHCompletion)completion {

    [[completion copy] autorelease];

    NSError * error = nil;

    // Upload the photo.

    // Set error if something goes wrong.

    if (completion) completion(error);

}
Want to Learn More?
WWDC 2011
  Session 308
  Session 210
WWDC 2010
  Session 206
  Session 211
https://github.com/rob-brown/RBCategories/blob/master/
GCD+RBExtras.c
Questions?

More Related Content

PPTX
Grand Central Dispatch
PDF
Blocks & GCD
PPT
iOS Multithreading
PDF
GCD and OperationQueue.
PPTX
Pune-Cocoa: Blocks and GCD
PDF
Multithreading and Parallelism on iOS [MobOS 2013]
KEY
Automatic Reference Counting
PDF
Tech Talk #4 : Multi - threading and GCD ( grand central dispatch ) in iOS - ...
Grand Central Dispatch
Blocks & GCD
iOS Multithreading
GCD and OperationQueue.
Pune-Cocoa: Blocks and GCD
Multithreading and Parallelism on iOS [MobOS 2013]
Automatic Reference Counting
Tech Talk #4 : Multi - threading and GCD ( grand central dispatch ) in iOS - ...

What's hot (20)

PDF
Grand Central Dispatch - iOS Conf SG 2015
KEY
Threading in iOS / Cocoa Touch
PPTX
Effective java - concurrency
PDF
Java Concurrency Gotchas
PDF
Java Concurrency in Practice
PPT
Java New Evolution
PPTX
Concurrency in Java
PDF
Objective-C Blocks and Grand Central Dispatch
PDF
Java Concurrency Idioms
PPT
Stoop 305-reflective programming5
PPTX
Node.js Workshop - Sela SDP 2015
PPTX
Concurrency Programming in Java - 07 - High-level Concurrency objects, Lock O...
PPTX
The Java memory model made easy
PPTX
Basics of Java Concurrency
PDF
Multithreading on iOS
PDF
How to Test Asynchronous Code (v2)
PDF
Why GC is eating all my CPU?
PDF
Realm.io par Clement Sauvage
PPT
Behavioral Reflection
ODP
Java Concurrency, Memory Model, and Trends
Grand Central Dispatch - iOS Conf SG 2015
Threading in iOS / Cocoa Touch
Effective java - concurrency
Java Concurrency Gotchas
Java Concurrency in Practice
Java New Evolution
Concurrency in Java
Objective-C Blocks and Grand Central Dispatch
Java Concurrency Idioms
Stoop 305-reflective programming5
Node.js Workshop - Sela SDP 2015
Concurrency Programming in Java - 07 - High-level Concurrency objects, Lock O...
The Java memory model made easy
Basics of Java Concurrency
Multithreading on iOS
How to Test Asynchronous Code (v2)
Why GC is eating all my CPU?
Realm.io par Clement Sauvage
Behavioral Reflection
Java Concurrency, Memory Model, and Trends
Ad

Viewers also liked (20)

PPT
Lecture 3 and 4 threads
PPTX
Programação Assíncrona com C# 5
PPTX
Edição mercado livre2
PDF
TDC 2012 Goiânia: Trilha .NET - Novidades do .NET Framework 4.5
PDF
IAsyncResult Pattern ou Asynchronous Programming Model (APM)
PDF
Programação assíncrona com C# 5 no Visual Studio 2013 [MVP ShowCast 2013 - DE...
PPT
Presentation final
PPT
PPTX
PPTX
History of the Corset
PPTX
PPTX
Multithread Programing in Java
ODP
Multithreading In Java
PDF
Programação assíncrona com C#
PPTX
Baroque and rococo architecture
PPTX
Rococo
PPT
Fashion through the decades
PPTX
Rococo art and architecture
PPT
Baroque n rococo
PPTX
Fashion History
Lecture 3 and 4 threads
Programação Assíncrona com C# 5
Edição mercado livre2
TDC 2012 Goiânia: Trilha .NET - Novidades do .NET Framework 4.5
IAsyncResult Pattern ou Asynchronous Programming Model (APM)
Programação assíncrona com C# 5 no Visual Studio 2013 [MVP ShowCast 2013 - DE...
Presentation final
History of the Corset
Multithread Programing in Java
Multithreading In Java
Programação assíncrona com C#
Baroque and rococo architecture
Rococo
Fashion through the decades
Rococo art and architecture
Baroque n rococo
Fashion History
Ad

Similar to Grand Central Dispatch Design Patterns (20)

DOCX
JAVA CONCEPTS AND PRACTICES
DOCX
Jist of Java
PDF
Advanced Node.JS Meetup
PPTX
Parallel & Concurrent ...
PPT
04 threads
PDF
Swift - One step forward from Obj-C
PPT
Threaded Programming
PDF
Objective-C Is Not Java
PDF
[2015/2016] JavaScript
ODP
Bring the fun back to java
PDF
How AngularJS Embraced Traditional Design Patterns
PPT
PPTX
Structural pattern 3
PPTX
Objective-c for Java Developers
PPTX
PPT
Java Tut1
PPT
Java Tutorial
PPT
Java tut1
PPT
Tutorial java
DOCX
Java 5 concurrency
JAVA CONCEPTS AND PRACTICES
Jist of Java
Advanced Node.JS Meetup
Parallel & Concurrent ...
04 threads
Swift - One step forward from Obj-C
Threaded Programming
Objective-C Is Not Java
[2015/2016] JavaScript
Bring the fun back to java
How AngularJS Embraced Traditional Design Patterns
Structural pattern 3
Objective-c for Java Developers
Java Tut1
Java Tutorial
Java tut1
Tutorial java
Java 5 concurrency

More from Robert Brown (13)

PDF
High level concurrency
PDF
Data Source Combinators
PDF
Elixir
PDF
PDF
Reactive Cocoa
PDF
UIKit Dynamics
PDF
iOS State Preservation and Restoration
KEY
Anti-Patterns
KEY
Pragmatic blocks
KEY
Grand Central Dispatch
KEY
Mac/iOS Design Patterns
KEY
Core Data
KEY
Quick Look for iOS
High level concurrency
Data Source Combinators
Elixir
Reactive Cocoa
UIKit Dynamics
iOS State Preservation and Restoration
Anti-Patterns
Pragmatic blocks
Grand Central Dispatch
Mac/iOS Design Patterns
Core Data
Quick Look for iOS

Recently uploaded (20)

PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PPTX
Cloud computing and distributed systems.
PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PDF
Unlocking AI with Model Context Protocol (MCP)
PPT
Teaching material agriculture food technology
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PDF
cuic standard and advanced reporting.pdf
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PDF
Mobile App Security Testing_ A Comprehensive Guide.pdf
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PPTX
A Presentation on Artificial Intelligence
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Cloud computing and distributed systems.
“AI and Expert System Decision Support & Business Intelligence Systems”
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
Unlocking AI with Model Context Protocol (MCP)
Teaching material agriculture food technology
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
cuic standard and advanced reporting.pdf
Per capita expenditure prediction using model stacking based on satellite ima...
Mobile App Security Testing_ A Comprehensive Guide.pdf
Digital-Transformation-Roadmap-for-Companies.pptx
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Network Security Unit 5.pdf for BCA BBA.
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Chapter 3 Spatial Domain Image Processing.pdf
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
A Presentation on Artificial Intelligence
20250228 LYD VKU AI Blended-Learning.pptx
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf

Grand Central Dispatch Design Patterns

  • 1. Grand Central Dispatch Design Patterns By Robert Brown @robby_brown
  • 3. Blocks Blocks are a proposed addition to C. Like a function pointer, except it also stores the context the block was created in. Similar to closures, lambdas, and anonymous functions in other languages.
  • 4. Blocks Declaration Syntax: returnType (^blockName) (Arguments) Blocks may be anonymous. Definition Syntax: ^ returnType (Arguments) { code; } The return type and arguments are optional. GCD provides function pointer variants to the block APIs.
  • 5. Blocks Blocks can modify local variables outside of their scope if the variables have the new __block keyword. Global and static variables can be modified without the __block keyword. Blocks automatically retain Objective-C objects, except objects that use the __block modifier. C objects must be manually retained. Beware of retain cycles.
  • 7. What is GCD? GCD is a lightweight multithreading engine. Uses a thread pool. Developers create queues of blocks rather than threads. Uses lock-less exclusion rather than mutual exclusion. Replaces blocking and polling APIs.
  • 8. Why Multithread on a Single Core? Keeps the UI responsive. UI code runs on the main thread. Everything else runs on a background thread. Prevents the main thread from blocking or waiting.
  • 9. Frequently Used APIs dispatch_async(queue, block); dispatch_once(token, block); dispatch_queue_create(name, type); dispatch_set_target_queue(object, queue); dispatch_get_global_queue(priority, flags); dispatch_release(object);
  • 10. Global Queues Four global queues: Main, Low, Default, and High. Only the main thread services the main queue. The three other queues determine the priority of background tasks. Enqueuing is thread safe.
  • 12. What is a Design Pattern? After working on related problems, patterns often appear in the solutions. Formalized description of best practice.
  • 14. dispatch_once Guaranteed to run only once for the lifetime of the application. Fast and thread safe. Very easy to use. Great for singletons and static class variables.
  • 15. The Old Way static MyObject * myObject = nil; + myObject { @synchronized(self) { if (!myObject) myObject = [MyObject new]; } return myObject; }
  • 16. Problems With @synchronized @synchronized is slow. When synchronizing on the class instance, all other methods that synchronize on it will temporarily block incoming messages. You can’t synchronize on the class variable since it is initially nil. Using a custom lock also faces the initialization problem.
  • 17. The GCD Way static MyObject * myObject = nil; + myObject { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ if (!myObject) myObject = [MyObject new]; }); return myObject; }
  • 19. Mutual Exclusion Mutual exclusion is classically handled by semaphores or locks. Both are most efficient when there is no sharing conflicts, (i.e. when you don’t need them) and don’t scale well. Queues are efficient and scale very well. In fact, queues are most efficient under high conflict.
  • 20. Thread-safe Access // myQueue must be a serial queue NSLock * lock = [NSLock new]; dispatch_async(myQueue, ^{ [lock lock]; [self setMySharedVariable:42]; [self setMySharedVariable:42]; }); [lock unlock];
  • 21. Enforcing Lockless Exclusion - (NSInteger)mySharedVariable { NSAssert(dispatch_get_current_queue() == myQueue, @“Wrong queue.”); return mySharedVariable; }
  • 22. Problems with Getters/ Setters We would rather have the compiler write our getters/ setters. This technique works well in other methods. Only immutable objects are fully protected this way.
  • 23. Enforcing Lockless Exclusion - (void)accessSharedVariableAsync:(void(^)(id sharedVariable))block { // myQueue must be a serial queue! dispatch_async(myQueue, ^{ block([self sharedVariable]); }); }
  • 24. Enforcing Lockless Exclusion - (void)accessSharedVariableSyncSafe:(void(^)(id sharedVariable))block { // myQueue must be a serial queue! if (dispatch_get_current_queue() == myQueue) block([self sharedVariable]); else dispatch_sync(myQueue, ^{ block([self sharedVariable]); }); }
  • 25. Compare to @synchronized [obj accessSharedDataAsync:^(id sharedVar) @synchronized ([obj sharedVar]) { { // Critical code here. // Critical code here. } } Fast - No Locks Slow - Recursive Lock Allows private access Must allow public access Synchronous or Asynchronous Synchronous Only Can be extended to access many shared Only single-value access. data values at once.
  • 27. Why Striding? Myth: My app will go faster if I multithread. Your app will only be faster if the work is parallelizable. Sometimes a block simply contains a loop, and each iteration can be run independently of the others. So, why not spread the iterations across many threads?
  • 28. One Thread dispatch_async(myQueue, ^{ for(int i = 0; i < 10; i++) [self doIndependentTask:i]; });
  • 29. dispatch_apply // myQueue must be a concurrent queue! dispatch_apply(10, myQueue, ^(size_t idx) { [self doIndependentTask:idx]; });
  • 30. Problems with dispatch_apply One thread per iteration may be overkill and result in high overhead costs. Solution: Use striding (i.e. have one thread run many iterations). Similar to loop unrolling. You may need to profile your app to find the ideal stride length.
  • 31. size_t stride = 4; size_t iterations = 10; size_t strideCount = iterations / stride; // myQueue must be a concurrent queue! dispatch_apply(strideCount, myQueue, ^(size_t idx) { size_t i = idx * stride; size_t stop = i + stride; do { [self doIndependentTask:i++]; } while (i < stop); }); // Pick up any left over iterations. for (size_t i = strideCount - (strideCount % stride); i < iterations; i++) [self doIndependentTask:i];
  • 33. What is a Continuation? Well, it’s complicated...take CS 330. Think of it like a completion block wrapped in a completion block wrapped in a completion block...
  • 34. Using Continuations The following steps are optional, but either 4 or 5 must be done. 1. Do some processing. 2. Wrap the completion block in another block. 3. Copy the block if it is going to cross threads (unnecessary with ARC). 4. Pass the completion block to someone else. 5. Execute the completion block.
  • 35. typedef void(^CHCompletion)(NSError * error); - (void)uploadPhoto:(NSString *)photoPath { // Do some pre-processing. [self processPhotoAtPath:photoPath completion:^(NSError * error) { if (error) dispatch_async(dispatch_get_main_queue(), ^{ // Inform user of error }); }]; }
  • 36. - (void)processPhotoAtPath:(NSString *)path completion: (CHCompletion)completion { [[completion copy] autorelease]; // Do some resizing and add a caption, then save the modified photo to a temporary file for memory efficiency. [self uploadProcessedPhotoAtPath:newPath completion:^(NSError * error) { // Delete the temporary file. if (completion) completion(error); }]; }
  • 37. - (void)uploadProcessedPhotoAtPath:(NSString *)path completion:(CHCompletion)completion { [[completion copy] autorelease]; NSError * error = nil; // Upload the photo. // Set error if something goes wrong. if (completion) completion(error); }
  • 38. Want to Learn More? WWDC 2011 Session 308 Session 210 WWDC 2010 Session 206 Session 211 https://github.com/rob-brown/RBCategories/blob/master/ GCD+RBExtras.c

Editor's Notes