Lecture #10: Blocks and Multithreading

Assignment #4 Task #2 requires to sort an array alphabetically. This can be implemented best using blocks which are explained in lecture ten in detail. Thus it is recommend to study this lecture before continuing with assignment #4.

Lecture ten is named “10. Blocks and Multithreading (October 27, 2011)” and can be found at iTunes. Its slides are available at Stanford.

The theoretical part of this lecture provides a short overview about UITabBarControllers and UINavigationItems as well as a detailed introduction to blocks and threading.

The UITabBarController has a NSArray as property which points to its embedded viewControllers. Each of those has a tabBarItem property allowing to manipulate the appearance inside the tab bar, e.g. placing a badge on top of the tab bar button:

self.tabBarItem.badgeValue = @“R”;

Analog, buttons and tool bar items of a UINavigationController are accesible via properties of its embedded view controllers, e.g:

@property (nonatomic, strong) UINavigationItem *navigationItem;
@property (nonatomic, copy) NSArray *leftBarButtonItems;
@property (nonatomic, strong) UIView *titleView;
@property (nonatomic, copy) NSArry *rightBarButtonItems;
@property (nonatomic, copy) UIBarButtonItem *backButtonItem;

Blocks are sequences of code used for

  • enumberation,
  • sorting,
  • view animations,
  • notfications,
  • error handlers,
  • completion handlers and
  • multithreading,

essentially where you have to provide an encapsulated piece of code to somebody else.

They start with a caret ^ followed by optional arguments inside parentheses () and the actual code inside curly braces {}. Inside the code local variables can be used read-only, if the have not been marked as __block during declaration, or if they are instance variables. Objects used inside a block receive a strong pointer until the block goes out of scope and thus can be messaged from inside a block. To prevent memory cycles when self is used inside a block __weak can be used to create weak pointers instead.

Types can be defined for variables that can hold blocks, e.g.:

typedef double (^unary_operation_t)(double op);

where the first double gives the return type of the block, unary_operation_t the name of the new type and double op the arguments for the block type. A variable for the type above could then look like:

unary_operation_t square;
square = ^(double operand) {
    return operand * operand;
}

and used like a C function:

double squareOfFive = square(5.0);

It is also possible to declare the variable above without prior type definition:

double (^square)(double op) = ^(double op) { return op * op; };

When a block is an argument to a method and is used immediately, often there is no type definition or name of the block, e.g.:

- (void)enumerateKeysAndObjectsUsingBlock:(void (^)(id key, id obj, BOOL *stop))block;

When defining a block, and the return type can be inferred from the code, the return type can be omitted. If there are no arguments the parentheses can be omitted as well. e.g.:

NSNumber *secret = [NSNumber numberWithDouble:42.0];
[brain addUnaryOperation:@“MoLtUaE” whichExecutesBlock:^(double operand) {
    return operand * [secret doubleValue];
}];

[UIView animateWithDuration:5.0 animations:^{
    view.opacity = 0.5;
}];

One of the major applications of blocks is Grand Central Dispatch which provides a C API for multi-threading. e.g.

// Creating and releasing queues
dispatch_queue_t dispatch_queue_create(const char *label, NULL);
void dispatch_release(dispatch_queue_t);

// Putting blocks in the queue
typedef void (^dispatch_block_t)(void);
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

// Getting the current or main queue
dispatch_queue_t dispatch_get_current_queue();
void dispatch_queue_retain(dispatch_queue_t);
dispatch_queue_t dispatch_get_main_queue();

The following example loads an external image asynchronously and puts it into an image view when ready:

dispatch_queue_t downloadQueue = dispatch_queue_create(“image downloader”, NULL);
dispatch_async(downloadQueue, ^{
     NSData *imageData = [NSData dataWithContentsOfURL:networkURL];
     dispatch_async(dispatch_get_main_queue(), ^{
         UIImage *image = [UIImage imageWithData:imageData];
         self.imageView.image = image;
         self.imageView.frame = CGRectMake(0, 0, image.size.width, image.size.height);
         self.scrollView.contentSize = image.size;
     });
});
dispatch_release(downloadQueue);

The demo of this lecture shows how to populate a table asynchronously. Its code is available at Stanford in two version: The actual code from the demo, as well as an extended version including additional features like adding sections to the table view and a working storybaord for the iPhone. The adjusted code is also available at github.

Facebooktwittergoogle_plusredditpinterestlinkedintumblrmailFacebooktwittergoogle_plusredditpinterestlinkedintumblrmail

Flattr this!

4 thoughts on “Lecture #10: Blocks and Multithreading”

      1. I think I just got it. =)
        It won’t create a memory cycle because the block has a strong pointer to self, but self isn’t the one with a strong pointer to the block, right?

Leave a Reply

Your email address will not be published. Required fields are marked *