Blocks                         and                 Grand Central Dispatch                        Matteo Battaglio         ...
Blocks                                 Pragma Nightgiovedì 7 febbraio 13
What are Blocks?         Blocks are:           • an extension to the C language and its derivatives                   Obje...
Benefits           • more functional style of coding           • less boilerplate code           • more readable code      ...
Definition           • ‘block’ is the name Objective-C gives to the                   concept of closure, that is:         ...
Syntax          int multiplier = 7;             Declaration of the variable                                               ...
Key features           • allow code to be passed around for later                   execution           • access to the lo...
Code example #1          int multiplier = 7;          // Declaring a block and assigning it to the variable ‘myBlock’     ...
Code example #2          // Inline use of a block literal (as an actual parameter of a function)          char *myCharacte...
Code example #3          // Declaring a function that takes a block as parameter          void myFunction(int (^aBlock)(vo...
Code example #4          // Defining a custom name for our block type to improve code style          typedef void (^MyBloc...
Variables caveats           • non-local variables in blocks are constant and                   read-only                  ...
__block            int myFunction() {                    __block int i = 0;                    void (^myBlock)(void) = ^{ ...
State representation           • blocks can use variables marked with __block to                   keep a state among call...
Information hiding                                                                    The outer block defines a local varia...
__block implications           • variables marked with __block are shared                   between their lexical scope an...
Memory concerns           • a block is allowed to access self            • self is passed as a strong reference           ...
Common scenarios in the SDK        Collection enumeration          NSArray *array = [NSArray arrayWithObjects:@"One", @"Tw...
Common scenarios in the SDK         View animations          - (void)animateView:(UIView*)view {              CGRect cache...
Common scenarios in the SDK        Notification observers            NSNotificationCenter *center = [NSNotificationCenter d...
Common scenarios in the SDK        Operations queues            NSOperationQueue *queue = [[NSOperationQueue alloc] init];...
Grand Central Dispatch                         Pragma Nightgiovedì 7 febbraio 13
What is Grand Central Dispatch?          Grand Central Dispatch (GCD) is:           • a set of language features and libra...
Concept           • GCD is based on the Thread Pool pattern            • a (small) number of threads is created           ...
Implementation           • dispatch queues           • dispatch sources           • dispatch groups           • dispatch s...
Dispatch queues         • execute tasks always in a first-in, first-out order         • 2 types:           • serial queues (...
Serial queues         • one and only one task running at a time         • the main dispatch queue is serial          • tie...
Creating serial queues          // Creating a serial dispatch queue          dispatch_queue_t queue;          queue = disp...
Concurrent queues         • tasks are started in order but run concurrently         • the system provides four concurrent ...
Creating concurrent queues          // Getting one of the four global dispatch queues          dispatch_queue_t global_que...
Using queues           • dispatch_async(queue,                block)                 • submits a block for asynchronous ex...
Using queues       • dispatch_after(when,                        queue, block)             • enqueue a block for execution...
Dispatch sources           • allow the client to register blocks or functions to                   execute asynchronously ...
Dispatch source example      dispatch_source_t CreateDispatchTimer(uint64_t interval,                                     ...
Dispatch groups           • are objects that allow several tasks to be grouped                   for later joining.       ...
Dispatch group example      dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);      d...
Dispatch semaphores           • useful for regulating the use of finite resources              // Example: limiting the num...
References           •       WWDC 2011 - session 308:                   Blocks and Grand Central Dispatch in Practice     ...
Thank You!                        matteo.battaglio@pragmamark.org                                                         ...
Upcoming SlideShare
Loading in …5
×

Objective-C Blocks and Grand Central Dispatch

3,359 views

Published on

Introduction to Objective-C's Blocks and Grand Central Dispatch technologies

Published in: Technology
0 Comments
5 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,359
On SlideShare
0
From Embeds
0
Number of Embeds
45
Actions
Shares
0
Downloads
62
Comments
0
Likes
5
Embeds 0
No embeds

No notes for slide

Objective-C Blocks and Grand Central Dispatch

  1. 1. Blocks and Grand Central Dispatch Matteo Battaglio Pragma Night @ Talent Gardengiovedì 7 febbraio 13
  2. 2. Blocks Pragma Nightgiovedì 7 febbraio 13
  3. 3. What are Blocks? Blocks are: • an extension to the C language and its derivatives Objective-C and C++, introduced by Apple • available in iOS SDK since version 4.0 • already used by plenty of iOS frameworks’ APIs Pragma Nightgiovedì 7 febbraio 13
  4. 4. Benefits • more functional style of coding • less boilerplate code • more readable code • simplify event-driven scenarios (i.e. callbacks) • simplify multi-threading Pragma Nightgiovedì 7 febbraio 13
  5. 5. Definition • ‘block’ is the name Objective-C gives to the concept of closure, that is: • a pointer to a function • a copy of some of the local variables of its higher-order function Pragma Nightgiovedì 7 febbraio 13
  6. 6. Syntax int multiplier = 7; Declaration of the variable Definition of the variable ‘myBlock’, ‘myBlock’. using a block literal. The ‘^’ tells that its type is a block. int (^myBlock)(int) = ^(int num) { return num * multiplier; }; Return type Parameter list Body of the block. The parameter is named ‘num’. Pragma Nightgiovedì 7 febbraio 13
  7. 7. Key features • allow code to be passed around for later execution • access to the local variables of the function they were declared in • mantain a state among calls Pragma Nightgiovedì 7 febbraio 13
  8. 8. Code example #1 int multiplier = 7; // Declaring a block and assigning it to the variable ‘myBlock’ int (^myBlock)(int) = ^(int num) { return num * multiplier; }; // Calling the block printf(myBlock(3)); // prints 21 Calling a block in no different than calling a function Pragma Nightgiovedì 7 febbraio 13
  9. 9. Code example #2 // Inline use of a block literal (as an actual parameter of a function) char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" }; qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) { char *left = *(char **)l; char *right = *(char **)r; return strncmp(left, right, 1); }); qsort_b() will internally call the block many times, in order to compare each pair of cells in the array // myCharacters is now { "Charles Condomine", "George", "TomJohn" } Pragma Nightgiovedì 7 febbraio 13
  10. 10. Code example #3 // Declaring a function that takes a block as parameter void myFunction(int (^aBlock)(void *, void *)); // Declaring a function that returns a block void (^myFunction(int a, int b))(double, double); Function name Function parameters The function’s return type is a block with signature void (^)(double, double) Pragma Nightgiovedì 7 febbraio 13
  11. 11. Code example #4 // Defining a custom name for our block type to improve code style typedef void (^MyBlockType)(double, double); // Variable and function declarations now look much more readable MyBlockType myBlock = ^(double a, double b) { printf("hey!"); }; MyBlockType myFunction(int a, int b, MyBlockType aBlock); Pragma Nightgiovedì 7 febbraio 13
  12. 12. Variables caveats • non-local variables in blocks are constant and read-only Trying to modify ‘i’ from inside the block results in a compilation error. • in order to make them ‘live’ and writable the __block type specifier must be added to their declaration Pragma Nightgiovedì 7 febbraio 13
  13. 13. __block int myFunction() { __block int i = 0; void (^myBlock)(void) = ^{ i++; printf("i has the value %d", i); // prints i has the value 1 }; } • what __block does is: • pass the variable by reference - rather than by value - to the block • create a strong (as opposed to weak) reference to that variable Pragma Nightgiovedì 7 febbraio 13
  14. 14. State representation • blocks can use variables marked with __block to keep a state among calls int myFunction() { __block int i = 0; void (^myBlock)(void) = ^{ i++; printf("i has the value %d", i); }; myBlock(); // prints i has the value 1 myBlock(); // prints i has the value 2 } Pragma Nightgiovedì 7 febbraio 13
  15. 15. Information hiding The outer block defines a local variable that is used inside the inner block to mantain a state: this way we are keeping the sum variable hidden to the rest of the program int array[] = {4, 5, 2, 6, 1}; qsort_b(array, 5, sizeof(int), ^(void) { __block int sum = 0; return ^(const void *a, const void *b) { sum += (int)a; return a - b; }; The inner block is what gets passed to the qsort_b() function }()); These parentheses tell us that the outer block is executed, and not passed to qsort_b. Pragma Nightgiovedì 7 febbraio 13
  16. 16. __block implications • variables marked with __block are shared between their lexical scope and all blocks and block copies declared or created within that scope • multiple blocks can simultaneously use a shared variable • when a block is copied (i.e. it is moved from the stack to the heap), they survive the destruction of their stack frame Pragma Nightgiovedì 7 febbraio 13
  17. 17. Memory concerns • a block is allowed to access self • self is passed as a strong reference • this could lead to a ‘retain cicle’ • trick: define a __weak reference to self int myFunction() { __weak MyObject weakSelf = self; void (^myBlock)(void) = ^{ [weakSelf someMethod]; } } Pragma Nightgiovedì 7 febbraio 13
  18. 18. Common scenarios in the SDK Collection enumeration NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @“Four”, nil]; It substitutes the for loop. Now the collections can enumerate themselves. [array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array[%d] = %@", idx, obj); }]; Setting *stop to YES inside the block will stop the enumeration [array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array[%d] = %@", idx, obj); } Making an enumeration concurrent ]; is a matter of adding an option! Pragma Nightgiovedì 7 febbraio 13
  19. 19. Common scenarios in the SDK View animations - (void)animateView:(UIView*)view { CGRect cacheFrame = [view frame]; [UIView animateWithDuration:1.5 animations: ^{ CGRect newFrame = [view frame]; newFrame.origin.y = newFrame.origin.y + 250.0; [view setFrame:newFrame]; [view setAlpha:0.5]; } completion: ^(BOOL finished) { if (finished) { sleep(1); [view setFrame:cacheFrame]; [view setAlpha:1.0]; } }]; } Pragma Nightgiovedì 7 febbraio 13
  20. 20. Common scenarios in the SDK Notification observers NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; [center addObserverForName:SomeNotificationName object:nil queue:mainQueue usingBlock:^(NSNotification *note) { NSLog(@"Notification received"); }]; Pragma Nightgiovedì 7 febbraio 13
  21. 21. Common scenarios in the SDK Operations queues NSOperationQueue *queue = [[NSOperationQueue alloc] init]; [queue addOperationWithBlock:^{ NSLog(@"This block is run in the operation"); }]; Wraps the block inside a NSOperation A single NSBlockOperation can execute multiple blocks concurrently NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"This block is run in the operation"); }]; [operation addExecutionBlock:^{ NSLog(@"NSBlockOperations can execute multiple blocks "); }]; [operation setCompletionBlock:^{ NSLog(@"This Code Runs Once The Operation Has Finished"); }]; Pragma Nightgiovedì 7 febbraio 13
  22. 22. Grand Central Dispatch Pragma Nightgiovedì 7 febbraio 13
  23. 23. What is Grand Central Dispatch? Grand Central Dispatch (GCD) is: • a set of language features and libraries to improve and simplify the act of writing concurrent code • more efficient than threads • implemented at all levels of APIs in iOS (BSD subsystem, CoreFoundation, Cocoa) Pragma Nightgiovedì 7 febbraio 13
  24. 24. Concept • GCD is based on the Thread Pool pattern • a (small) number of threads is created • (possibly lots of) tasks are added to queues in order to be executed • an algorithm handles the creation/destruction of threads, and the scheduling of tasks Pragma Nightgiovedì 7 febbraio 13
  25. 25. Implementation • dispatch queues • dispatch sources • dispatch groups • dispatch semaphores Pragma Nightgiovedì 7 febbraio 13
  26. 26. Dispatch queues • execute tasks always in a first-in, first-out order • 2 types: • serial queues (aka private dispatch queues) • one and only one task running at a time • the main dispatch queue is a peculiar one • concurrent queues (aka global dispatch queues) • tasks started in order but run concurrently • four such queues, differing only by priority level, are made available by the os Pragma Nightgiovedì 7 febbraio 13
  27. 27. Serial queues • one and only one task running at a time • the main dispatch queue is serial • tied to the main thread and application’s run loop • interleaves queued tasks with other event sources • often used as the key synchronization point for the application Pragma Nightgiovedì 7 febbraio 13
  28. 28. Creating serial queues // Creating a serial dispatch queue dispatch_queue_t queue; queue = dispatch_queue_create("com.example.MyQueue", NULL); // Getting the dispatch queue on which the currently executing block is running dispatch_queue_t current_queue; current_queue = dispatch_get_current_queue(); // Getting the main dispatch queue dispatch_queue_t main_queue; main_queue = dispatch_get_main_queue(); Pragma Nightgiovedì 7 febbraio 13
  29. 29. Concurrent queues • tasks are started in order but run concurrently • the system provides four concurrent queues • they are global to the application • they differ only by priority level Pragma Nightgiovedì 7 febbraio 13
  30. 30. Creating concurrent queues // Getting one of the four global dispatch queues dispatch_queue_t global_queue; global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // The four priority levels, ranked high to low, are DISPATCH_QUEUE_PRIORITY_HIGH DISPATCH_QUEUE_PRIORITY_DEFAULT DISPATCH_QUEUE_PRIORITY_LOW DISPATCH_QUEUE_PRIORITY_BACKGROUND // Creating a concurrent dispatch queue dispatch_queue_t queue; queue = dispatch_queue_create("com.example.MyQueue", DISPATCH_QUEUE_CONCURRENT); Pragma Nightgiovedì 7 febbraio 13
  31. 31. Using queues • dispatch_async(queue, block) • submits a block for asynchronous execution on a dispatch queue and returns immediately • dispatch_sync(queue, block) • submits a block object for execution on a dispatch queue and waits until that block completes Pragma Nightgiovedì 7 febbraio 13
  32. 32. Using queues • dispatch_after(when, queue, block) • enqueue a block for execution at the specified time • dispatch_apply(iterations, queue, block) • submits a block to a dispatch queue for multiple invocations • dispatch_once(queue, block) • executes a block object once and only once for the lifetime of an application Pragma Nightgiovedì 7 febbraio 13
  33. 33. Dispatch sources • allow the client to register blocks or functions to execute asynchronously upon system events • unlike manually-put tasks, they remain attached to their queue, and submit their associated task to it whenever the corresponding event occurs • to prevent backlogging, they can coalesce events • types of sources: signal, timer, descriptor, process, Mach port, custom Pragma Nightgiovedì 7 febbraio 13
  34. 34. Dispatch source example dispatch_source_t CreateDispatchTimer(uint64_t interval, uint64_t leeway, dispatch_queue_t queue, dispatch_block_t block) { dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); if (timer) { dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), interval, leeway); dispatch_source_set_event_handler(timer, block); dispatch_resume(timer); } return timer; } void MyCreateTimer() { dispatch_source_t aTimer = CreateDispatchTimer(30ull * NSEC_PER_SEC, 1ull * NSEC_PER_SEC, dispatch_get_main_queue(), ^{ MyPeriodicTask(); }); // Store it somewhere for later use. if (aTimer) { MyStoreTimer(aTimer); } } Pragma Nightgiovedì 7 febbraio 13
  35. 35. Dispatch groups • are objects that allow several tasks to be grouped for later joining. • a task can be added to a queue as a member of a group, and then the client can use the group object to wait until all of the tasks in that group have completed Pragma Nightgiovedì 7 febbraio 13
  36. 36. Dispatch group example dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_group_t group = dispatch_group_create(); // Add a task to the group dispatch_group_async(group, queue, ^{ // Some asynchronous work }); // // Do some other work while the tasks execute... // // When you cannot make any more forward progress, // wait on the group to block the current thread. dispatch_group_wait(group, DISPATCH_TIME_FOREVER); // Release the group when it is no longer needed. dispatch_release(group); Pragma Nightgiovedì 7 febbraio 13
  37. 37. Dispatch semaphores • useful for regulating the use of finite resources // Example: limiting the number of file descriptors open concurrently // Create the semaphore, specifying the initial pool size dispatch_semaphore_t fd_sema = dispatch_semaphore_create(getdtablesize() / 2); // Wait for a free file descriptor dispatch_semaphore_wait(fd_sema, DISPATCH_TIME_FOREVER); fd = open("/etc/services", O_RDONLY); // Release the file descriptor when done close(fd); dispatch_semaphore_signal(fd_sema); Pragma Nightgiovedì 7 febbraio 13
  38. 38. References • WWDC 2011 - session 308: Blocks and Grand Central Dispatch in Practice • Apple documentation • Blocks Programming Topics • Concurrency Programming Guide • Grand Central Dispatch (GCD) Reference • Book: Pro Multithreading and Memory Management for iOS and OS X: with ARC, Grand Central Dispatch, and Blocks Pragma Nightgiovedì 7 febbraio 13
  39. 39. Thank You! matteo.battaglio@pragmamark.org Pragma Nightgiovedì 7 febbraio 13

×