1. Dispatch queue of GCD
Http://www.cnblogs.com/scorpiozj/archive/2011/07/25/2116459.html
2. GCD magic in IOS
Http://blog.csdn.net/favormm/article/details/6453260
3. There are a lot of official content
Http://developer.apple.com/library/ios/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
Http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1
4. Details about Concurrent Dispatch queues for iOS app development
Http://mobile.51cto.com/iphone-283323.htm
5. Stanford lecture on GCD
Http://www.stanford.edu/class/cs193p/cgi-bin/drupal/system/files/lectures/Lecture%2013_0.pdf
GCD is actually a simplified version of multithreading. GCD and block are brothers, so you need to understand the block before learning GCD. If you don't know it, it's okay. You can see the code.
Function prototype
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
Async indicates asynchronous running. (In addition to async, there are also sync and delay. This article uses async as an example ).
Queue is who you handed the task.
Block indicates what you want to do.
There are three types of queue
Main:Tasks execute serially on your application's main thread
Concurrent:Tasks start executing in FIFO order, but can run concurrently.
Serial:Tasks execute one at a time in FIFO order
(1) Serial queues (Serial Queue), also known as private scheduling queue, is generally used for Synchronous access to specific resources. We can create any number of serial queues as needed. Each serial queue is concurrent.
(2) Parallel queue, also known as global dispatch queue. Although parallel queues can run multiple tasks concurrently, the execution sequence of the tasks starts is the same as that of the tasks added to the queue. We cannot create parallel scheduling queues by ourselves. There are only three available global concurrent queues.
(3) Main dispatch queue is a globally available serial queue that executes tasks on the main thread of the application. Tasks in this queue alternate with the event source to be executed in the main loop of the application. Because it runs in the main thread of the application, main queue is often used as a synchronization point of the application.
First read a piece of code
@interface UIImageView (DispatchLoad) - (void) setImageFromUrl:(NSString*)urlString; - (void) setImageFromUrl:(NSString*)urlString completion:(void (^)(void))completion; @end
#import "UIImageView+DispatchLoad.h" @implementation UIImageView (DispatchLoad) - (void) setImageFromUrl:(NSString*)urlString { [self setImageFromUrl:urlString completion:NULL]; } - (void) setImageFromUrl:(NSString*)urlString completion:(void (^)(void))completion { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"Starting: %@", urlString); UIImage *avatarImage = nil; NSURL *url = [NSURL URLWithString:urlString]; NSData *responseData = [NSData dataWithContentsOfURL:url]; avatarImage = [UIImage imageWithData:responseData]; NSLog(@"Finishing: %@", urlString); if (avatarImage) { dispatch_async(dispatch_get_main_queue(), ^{ self.image = avatarImage; }); dispatch_async(dispatch_get_main_queue(), completion); } else { NSLog(@"-- impossible download: %@", urlString); } }); } @end
The above code mainly implements asynchronous image loading. Break down: 1> Add to GCD queuedispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
This code is mainly used to add the image loading block to the queue,
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
This is the global dispatch queue, which has only three system queues. 2> load the image. This filtering 3> notifies or updates the main thread
dispatch_async(dispatch_get_main_queue(), ^{ self.image = avatarImage; }); dispatch_async(dispatch_get_main_queue(), completion);
"One advantage of block is that it can use variables out of its own scope. For example, a block can read the variable value of its parent scope. This value is copied to the data structure of block heap. When a block is added to the dispatch queue, these values are generally read-only ."
The updated UI can only be implemented in the main thread, so the main thread function completion is called.
This completes the asynchronous image loading process.
The serial queue is useful when you want to execute tasks in a specific order. The serial queue only executes one task at the same time. We can use serial queues instead of locks to protect shared data. Unlike locks, a serial queue ensures that tasks are executed in a predictable order.Different from the concurrent queue, we need to create and manage the serial queue by ourselves. We can create any number of serial queues. When creating a serial queue, We Should for some purpose, such as protecting resources or Synchronizing some key actions of the application.
The following code describes how to create a custom serial queue. The dispath_queue_create function requires two parameters: queue name and queue attribute. The debugger and performance tool display the queue name to help us track how tasks are executed. The queue attributes are retained for future use and should be null.
- dispatch_queue_t queue;
- queue = dispatch_queue_create("com.example.MyQueue", NULL);
In addition to the custom queue created by myself, the system will automatically create a serial queue for me and bind it with the main thread of the application. The following describes how to obtain it.
Post several sections of Stanford's GCD code, which gradually demonstrates how to correct errors, which are used as a serial queue
1. This is the original code
- (void)viewWillAppear:(BOOL)animated{ NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 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;}
2. This is the code using gcdd, with three errors in it
- (void)viewWillAppear:(BOOL)animated{ dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); dispatch_async(downloadQueue, ^{ NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 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; });}
3. The first error. UI update can only be performed in the main thread problem! Uikit callcan only happen in the main thread! After correction:
- (void)viewWillAppear:(BOOL)animated{ dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); dispatch_async(downloadQueue, ^{ NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:photo.URL]; 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; });}); }
4. The second error occurs. nsmanagedobjectcontext is NOT thread-safe. It is dangerous to access member variables in GCD. Problem! Nsmanagedobjectcontext is NOT thread safe,
So we can't call photo. url in downloadqueue's t
After correction:
- (void)viewWillAppear:(BOOL)animated{ NSString *url = photo.URL; dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); dispatch_async(downloadQueue, ^{ NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:url]; 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;}); });}
5. The third error is that the queue is not released after creation, causing memory leakage.
- (void)viewWillAppear:(BOOL)animated{ NSString *url = photo.URL; dispatch_queue_t downloadQueue = dispatch_queue_create(“Flickr downloader”, NULL); dispatch_async(downloadQueue, ^{ NSData *imageData = [FlickrFetcher imageDataForPhotoWithURLString:url]; 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); //won’tactuallygoawayuntilqueueisempty }