Top Banner
Pragma Night @ Talent Garden Blocks and Grand Central Dispatch Matteo Battaglio giovedì 7 febbraio 13
39

Blocks and GCD(Grand Central Dispatch)

Jun 14, 2015

Download

Technology

How to use Block operations and use of GCD
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Blocks and GCD(Grand Central Dispatch)

Pragma Night @ Talent Garden

Blocksand

Grand Central Dispatch

Matteo Battaglio

giovedì 7 febbraio 13

Page 2: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Blocks

giovedì 7 febbraio 13

Page 3: Blocks and GCD(Grand Central Dispatch)

Pragma Night

What are Blocks?

• 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

Blocks are:

giovedì 7 febbraio 13

Page 4: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Benefits

• more functional style of coding

• less boilerplate code

• more readable code

• simplify event-driven scenarios (i.e. callbacks)

• simplify multi-threading

giovedì 7 febbraio 13

Page 5: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 6: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Syntax

int multiplier = 7;

int (^myBlock)(int) = ^(int num) { return num * multiplier; };

Declaration of the variable ‘myBlock’.

The ‘^’ tells that its type is a block.

Return type Parameter list

Definition of the variable ‘myBlock’, using a block literal.

The parameter is named ‘num’.

Body of the block.

giovedì 7 febbraio 13

Page 7: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 8: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 9: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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);});

// myCharacters is now { "Charles Condomine", "George", "TomJohn" }

qsort_b() will internally call the block many times, in order to compare each pair of cells in the array

giovedì 7 febbraio 13

Page 10: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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 signaturevoid (^)(double, double)

giovedì 7 febbraio 13

Page 11: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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);

giovedì 7 febbraio 13

Page 12: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 13: Blocks and GCD(Grand Central Dispatch)

Pragma Night

__block

• 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

int myFunction() { __block int i = 0; void (^myBlock)(void) = ^{ i++; printf("i has the value %d", i); // prints 'i has the value 1' }; }

giovedì 7 febbraio 13

Page 14: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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' }

giovedì 7 febbraio 13

Page 15: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Information hiding

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 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

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.

giovedì 7 febbraio 13

Page 16: Blocks and GCD(Grand Central Dispatch)

Pragma Night

__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

giovedì 7 febbraio 13

Page 17: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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]; } }

giovedì 7 febbraio 13

Page 18: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Common scenarios in the SDK

NSArray *array = [NSArray arrayWithObjects:@"One", @"Two", @"Three", @“Four”, nil];

[array enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array[%d] = %@", idx, obj); }];

[array enumerateObjectsWithOptions: NSEnumerationConcurrent usingBlock: ^(id obj, NSUInteger idx, BOOL *stop) { NSLog(@"array[%d] = %@", idx, obj); } ];

It substitutes the for loop.Now the collections can enumerate themselves.

Collection enumeration

Setting *stop to YES inside the block will stop the enumeration

Making an enumeration concurrent is a matter of adding an option!

giovedì 7 febbraio 13

Page 19: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Common scenarios in the SDK

- (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]; } }];}

View animations

giovedì 7 febbraio 13

Page 20: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Common scenarios in the SDK

NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

[center addObserverForName:SomeNotificationName object:nil queue:mainQueue usingBlock:^(NSNotification *note) { NSLog(@"Notification received"); }];

Notification observers

giovedì 7 febbraio 13

Page 21: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Common scenarios in the SDK

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

[queue addOperationWithBlock:^{ NSLog(@"This block is run in the operation"); }];

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"); }];

Operations queues

Wraps the block inside a NSOperation

A single NSBlockOperation can execute multiple blocks concurrently

giovedì 7 febbraio 13

Page 22: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Grand Central Dispatch

giovedì 7 febbraio 13

Page 23: Blocks and GCD(Grand Central Dispatch)

Pragma Night

What is Grand Central Dispatch?

• 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)

Grand Central Dispatch (GCD) is:

giovedì 7 febbraio 13

Page 24: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 25: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Implementation

• dispatch queues

• dispatch sources

• dispatch groups

• dispatch semaphores

giovedì 7 febbraio 13

Page 26: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 27: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 28: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Creating serial queues

// Creating a serial dispatch queuedispatch_queue_t queue;queue = dispatch_queue_create("com.example.MyQueue", NULL);

// Getting the dispatch queue on which the currently executing block is runningdispatch_queue_t current_queue;current_queue = dispatch_get_current_queue();

// Getting the main dispatch queuedispatch_queue_t main_queue;main_queue = dispatch_get_main_queue();

giovedì 7 febbraio 13

Page 29: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 30: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Creating concurrent queues

// Getting one of the four global dispatch queuesdispatch_queue_t global_queue;global_queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

// The four priority levels, ranked high to low, areDISPATCH_QUEUE_PRIORITY_HIGHDISPATCH_QUEUE_PRIORITY_DEFAULTDISPATCH_QUEUE_PRIORITY_LOWDISPATCH_QUEUE_PRIORITY_BACKGROUND

// Creating a concurrent dispatch queuedispatch_queue_t queue;queue = dispatch_queue_create("com.example.MyQueue", DISPATCH_QUEUE_CONCURRENT);

giovedì 7 febbraio 13

Page 31: Blocks and GCD(Grand Central Dispatch)

Pragma Night

• 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

Using queues

giovedì 7 febbraio 13

Page 32: Blocks and GCD(Grand Central Dispatch)

Pragma Night

• 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

Using queues

giovedì 7 febbraio 13

Page 33: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 34: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Dispatch source exampledispatch_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); }}

giovedì 7 febbraio 13

Page 35: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 36: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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 groupdispatch_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);

giovedì 7 febbraio 13

Page 37: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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);

giovedì 7 febbraio 13

Page 38: Blocks and GCD(Grand Central Dispatch)

Pragma Night

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

giovedì 7 febbraio 13

Page 39: Blocks and GCD(Grand Central Dispatch)

Pragma Night

Thank You!

[email protected]

giovedì 7 febbraio 13