Grand Central Dispatch
With GCD, you can make your app responsive. Threading is hard. Using GCD makes it simple and fun. You need not do explicit thread management. Cool!
Keeping your app responsive:
1. Do not block the main thread
2. Move work to another thread
3. Update UI back on main threaad
Code without GCD:
- (void)addTweetWithMsg:(NSString*)msg url:(NSURL*)url {
// Controller UI callback on main thread
DTweet *tw = [[DTweet alloc] initWithMsg:msg];
[tweets addTweet:tw display:YES];
tw.img = [imageCache getImgFromURL:url];//bottle neck
[tweets updateTweet:tw display:YES];
[tw release];
}
Code with GCD:
- (void)addTweetWithMsg:(NSString*)msg url:(NSURL*)url {
// Controller UI callback on main thread
DTweet *tw = [[DTweet alloc] initWithMsg:msg];
[tweets addTweet:tw display:YES];
dispatch_async(image_queue, ^{
tw.img = [imageCache getImgFromURL:url];
dispatch_async(main_queue, ^{
[tweets updateTweet:tw display:YES];
});
});
[tw release];
}
GCD Queues
1. Lightweight list of blocks
2. Enqueue/dequeue is FIFO
3. Enqueue with dispatch_async()
4. Dequeue by automatic thread or main thread
Main Queue
1. Executes blocks one at a time on main thread
2. Cooperates with the UIKit main run loop
3. dispatch_get_main_queue()
Creating your own queues
1. Execute blocks one at a time
2. On automatic helper thread
3. “Queue up” background work
dispatch_queue_t queue;
queue = dispatch_queue_create(“com.example.purpose”, NULL);
dispatch_release(queue);
Queues Instead of Locks
1. Enqueuing is thread-safe.
2. Execution is serial
3. Protect access to shared data
4. Queues are lightweight
Managing Queue Lifetime
1. Queues are reference counted. dispatch_retain() / dispatch_release()
2. GCD retains parameters to dispatch API as necessary
3. Ensure correct queue lifetime across asynchronous operations
4. Ensure objects captured by blocks are valid when blocks are executed
5. Objective-c objects are auto-retained/released
6 Other objects must be retained by your code. CFRetain() / CFRelease()
- (void)asyncParseData:(NSData *)date
queue:(dispatch_queue_t)queue
block:(void (^)(id result))block {
dispatch_retain(queue);
dispatch_async(self.parse_queue, ^{
id result = [self parseData:data];
dispatch_async(queue, ^{
block(result);
});
dispatch_release(queue);
});
}
App Design with Queues
Demo app tasks
1. Receive and parse network stream
2. Maintain message history
3. Fetch and cache images
4. Display user interface
Without GCD
NSData *d = [twitterStream receiveData];
DTweet *tw = [[DTweet alloc] initWithData:d];
[[tweets addTweet:tw];
[viewController displayTweet:tw]; });
tw.img = [imageCache getImgFromURL:tw.url];
[viewController updateTweetDisplay:tw];
[tw release];
With GCD
dispatch_async(network_queue, ^{
NSData *d = [twitterStream receiveData];
DTweet *tw = [[DTweet alloc] initWithData:d];
dispatch_async(tweets_queue, ^{
[[tweets addTweet:tw];
dispatch_async(main_queue, ^{
[viewController displayTweet:tw]; });
});
dispatch_async(image_queue, ^{
tw.img = [imageCache getImgFromURL:tw.url];
dispatch_async(main_queue, ^{
[viewController updateTweetDisplay:tw];
});
});
});
[tw release];
});
Pitfalls
1. Avoid blocking per-subsystem queues
2. Be careful when waiting. (deadlock)
3. Blocked worker threads consume resources
Responding to External Events
Dispatch sources
1. Monitor external events
- Files, Network Sockets, Directories, Timers
2. Event handlers can be delivered to any queue
3. Use sources to replace polling or blocking API calls
4. See session 211:
Simplifying iPhone App Development with Grand Central Dispatch
Where do I find GCD?
1. GCD is part of libSystem.dylib
2. #include <dispatch/dispatch.h>
WWDC2010 Session206 Introducing Blocks and Grand Central Dispatch on iPhone
Author: Kevin van Vechten - Manager, Core OS
No comments:
Post a Comment