Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pragmatic Blocks

Pragmatic Blocks

Blocks are a powerful language feature. However, they are underused and under-appreciated in Objective-C, especially compared to Ruby. My intent is to make blocks easy to understand and show many practical uses of blocks.

Rob Brown

April 12, 2012
Tweet

More Decks by Rob Brown

Other Decks in Programming

Transcript

  1. Objectives Introduce the concepts behind blocks Touch lightly on Objective-C

    syntax Focus on practical applications of blocks
  2. What are blocks? Pieces of code that can be stored

    and executed when needed Also known as lambdas, closures, anonymous functions, first-class functions, higher-order functions Can be passed as a parameter, returned from a method/function, and stored in data structures Blocks make adding new features to a language easy
  3. What does “closure” mean? Blocks store all the variables that

    are in scope when the block is created Closure makes it possible to store a block indefinitely, then restore the context at will Objective-C objects are automatically retained/released C objects must be manually retained/released
  4. Block Syntax Declaration Syntax: returnType (^blockName) (Arguments) Definition Syntax: ^

    returnType (Arguments) { code; } The return type and arguments are optional.
  5. Block Syntax Example: returnType (^block)(args) = ^(args) { ... };

    Block types are ugly, use typedef: typedef returnType (^MyBlock)(args); MyBlock block = ^(args) { ... };
  6. Gotchas Retain loops Xcode profiler will warn you of block

    retain loops Unlike regular Objective-C objects, blocks are created on the stack Be sure to call -copy if you need it to live beyond the current stack frame Make sure to de-stackify blocks before storing them in a data structure
  7. Callbacks Most blocks are some form of callback Since blocks

    have closure, they can restore the caller’s context without any effort on our part
  8. Completion Blocks Most common use of blocks in Objective-C A

    callback that happens only after some task has finished Some operations take an unknown amount of time
  9. Completion Blocks Object A Object B Block Object A calls

    Object B and passes a completion block.
  10. Partial Completion Sometimes it may take a long time for

    an operation to complete The callee can periodically return partial results The caller accumulates the results The UI appears more responsive
  11. Continuations Think of it like a completion block wrapped in

    a completion block wrapped in a completion block... Essentially building your own runtime stack
  12. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  13. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block Object A calls Object B and passes a completion block. So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  14. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block Object A and Object B need to know when Object C finishes. So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  15. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  16. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  17. Object C finishes executing and calls the completion block. Continuations

    Object A Object B Object C Block So, Object B wraps Object A’s block in a new completion block. Object B then calls Object C with the new completion block.
  18. Multithreading: GCD Grand Central Dispatch (GCD) makes heavy use of

    blocks Blocks are not tied to a thread until they are executed Blocks can be queued up without blocking threads Threads can spend more time running and less time waiting
  19. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  20. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  21. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  22. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  23. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  24. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  25. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  26. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  27. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  28. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  29. Multithreading: GCD 2-Core Processor Block A Block B Thread 1

    Block C Thread 3 Block D Thread Pool Concurrent Queue Thread 2
  30. Block Delegation Delegates are protocols that specify method callbacks These

    method callbacks can be easily replaced with block callbacks Rule of thumb: 3 or less delegate callbacks should be handled using blocks.
  31. Block Delegation Advantages: No additional protocols No need to conform

    to a protocol Easy to change block callbacks dynamically
  32. Template Method Sometimes algorithms differ by only a few lines

    Those few lines can be replaced by a virtual method Subclasses define the virtual method
  33. Template Method Let’s use blocks instead! Advantages: No need for

    subclassing May not need a new class at all Template can be changed dynamically
  34. Lock Handling // Python convenient lock handler with myLock: //

    Do something // Can’t forget to lock/unlock
  35. Builder Pattern Some objects have complex structures that vary widely

    between uses Examples: Database tables, UITableView A block can define the construction of an object
  36. Builder Pattern // Ruby on Rails database table construction create_table

    :person do |t| t.string :name, null: false t.integer :age, null: false t.float :weight end
  37. Builder Pattern // Contrived example, but very feasible. // Creating

    a custom table view form. [RBTableView tableViewUsingBlock:^(RBTableView * t) { [t addStringField:@“name” required:YES]; [t addIntegerField:@“age” required:YES]; [t addFloatField:@“weight” required:NO]; }];
  38. Lockless Exclusion Accessor Thread-sensitive code is called critical code GCD

    allows for lockless-exclusion Lockless code is faster than lock code
  39. Lockless Exclusion Accessor Multi-threading challenges: Multi-threaded code must be properly

    synchronized It’s easy to forget to add thread-safety code
  40. Lockless Exclusion Accessor Solution: Have another object handle thread-safety Put

    critical code in a block Give the block to the thread-safety handler
  41. Lockless Exclusion Accessor - (void)accessSharedDataAsync:(void(^)(id sharedData))block { NSParameterAssert(block); // myQueue

    must be a serial queue! dispatch_async(myQueue, ^{ block([self sharedData]); }); }
  42. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  43. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  44. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  45. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  46. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  47. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  48. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  49. Block A Block B Shared Data Serial Queue Block C

    Shared Data Manager Lockless Exclusion Accessor LEA
  50. Read/Write LEA Code that only reads from shared memory doesn’t

    need exclusive access Code that writes to shared memory needs exclusive access GCD barrier blocks and concurrent queues are a perfect solution
  51. Read/Write LEA // Read-only LEA - (void)accessSharedDataReadOnlyAsync:(void(^)(id sharedData))block { NSParameterAssert(block);

    // myQueue must be a concurrent queue! dispatch_async([self myQueue], ^{ block([self sharedData]); }); }
  52. Read/Write LEA // Read/write LEA - (void)accessSharedDataReadWriteAsync:(void(^)(id sharedData))block { NSParameterAssert(block);

    // myQueue must be a concurrent queue! dispatch_barrier_async([self myQueue], ^{ block([self sharedData]); }); }
  53. // All-in-one R/W-LEA - (void)accessSharedDataAsyncReadOnly:(BOOL)readOnly withBlock:(void(^)(id sharedData))block { if (readOnly)

    dispatch_async([self myQueue], ^{ block([self sharedData]); }); else dispatch_barrier_async([self myQueue], ^{ block([self sharedData]); }); } Read/Write LEA
  54. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  55. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  56. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  57. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  58. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  59. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  60. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  61. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  62. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  63. Read/Write LEA Shared Data Concurrent Queue Read Block Read Block

    Write Block Read Block Read Block Shared Data Manager R/W-LEA
  64. Homework I have only touched the surface of what blocks

    can do Explore and find other design patterns you can convert to use blocks
  65. Want to Learn More? Blocks are best learned by playing

    with them Learn Ruby “The Pickaxe” Learn Racket 10 Uses for Blocks My Blog