blocks and gcd(grand central dispatch)

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

Upload: jigar-maheshwari

Post on 14-Jun-2015

301 views

Category:

Technology


0 download

DESCRIPTION

How to use Block operations and use of GCD

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