实现代码:
CGDHelper
- /*
- * Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。
- * 系统要求:iOS4.0以上。
- */
- #import <Foundation/Foundation.h>
- /// enum 声明 /
- //队列优先级
- typedef enum
- {
- GlobalQueuePriorityDefault = 0,
- GlobalQueuePriorityHigh = 2,
- GlobalQueuePriorityLow = -2,
- GlobalQueuePriorityBackground = INT16_MIN
- } GlobalQueuePriority;
- //阻塞、非阻塞
- typedef enum
- {
- PerformBlockFeatureChoke,
- PerformBlockFeatureUnchoke
- } PerformBlockFeature;
- //网络请求方法
- typedef enum GCDHelperHttpRequestMethod
- {
- GCDHelperHttpRequestMethodGET = 0,
- GCDHelperHttpRequestMethodPOST
- } GCDHelperHttpRequestMethod;
- /// Block 声明 /
- //返回值void
- typedef void (^GCDBlock) (void);
- typedef void (^GCDBlock1_Size_t) (size_t index);
- typedef void (^GCDBlock1_Int) (int index);
- typedef void (^GCDBlock1_Bool) (BOOL flag);
- typedef void (^GCDBlock1_Float) (float index);
- typedef void (^GCDBlock1_Obj) (id object);
- //返回值void,两个形式参数
- typedef void (^GCDBlock2) (id object1, size_t index);
- typedef void (^GCDBlock2_Obj_Int) (id object1, int index);
- typedef void (^GCDBlock2_Obj_Obj) (id object1, id object2);
- //有返回值
- typedef id (^GCD_Obj_Block_Obj) (id object);
- typedef id (^GCD_Obj_Block_Void) (void);
- typedef void (^GCDHttpRequestBlock) (NSURLResponse *response, NSError *error, NSData *data);
- /// GCDHelper 声明 /
- @interface GCDHelper : NSObject
- /* 获取3种队列 */
- + (dispatch_queue_t) gcdMainQueue;
- + (dispatch_queue_t) gcdGlobalQueue:(GlobalQueuePriority) priority;
- + (dispatch_queue_t) gcdCustomQueue:(NSString *) queueName;
- //后台执行
- + (void) gcdPerformBlockAsynchronous:(GCDBlock) block;
- //后台获取数据后,回到主线程
- + (void) gcdPerformBlockAsynchronous:(GCDBlock) blockAsyn
- finishOnMainQueue:(GCDBlock) blockM;
- /* 3种队列上执行Block
- *
- * 是否阻塞执行:(PerformBlockFeature) feature
- * 全局队列优先级:(GlobalQueuePriority) priority
- */
- + (void) gcdPerformBlockOnMainQueue:(GCDBlock) block feature:(PerformBlockFeature) feature;
- + (void) gcdPerformBlockOnGlobalQueue:(GCDBlock) block
- feature:(PerformBlockFeature) feature
- priority:(GlobalQueuePriority) priority;
- + (void) gcdPerformBlockOnCustomQueue:(GCDBlock) block
- feature:(PerformBlockFeature) feature
- name:(NSString *) queueName;
- //延迟执行方法
- + (void) gcdPerformBlock:(GCDBlock) block
- onQueue:(dispatch_queue_t) queue
- delaySecond:(int64_t) second;
- //只执行一次
- + (void) gcdPerformBlockOnce:(GCDBlock) block;
- //并发
- + (void) gcdBatchPerformBlocks:(NSArray *) blockArray finally:(GCDBlock) finallyBlock;
- + (void) gcdBatchPerformBlockWithData:(NSArray *) dataArray
- maxConcurrentOperationCount:(uint) count
- handleBlock:(GCDBlock1_Obj) block
- finally:(GCDBlock1_Obj) finallyBlock;
- @end
- /// 图片下载 /
- @interface GCDHelper (ImageDownload)
- - (void) gcdImageWithURLString:(NSString *) URLString;
- - (void) gcdImageWithURLString:(NSString *) URLString completion:(GCDBlock2_Obj_Obj) completion;
- @end
- /// 网络请求 /
- GCDBlock1_Bool _netWorkBlock;
- @interface GCDHelper (NetworkConnect)
- //网络连接判断、实时监控
- - (void) gcdNetWorkGuarder:(NSString *) hostname withBlock:(GCDBlock1_Bool) block;
- @end
- @interface GCDHelper (HttpRequest)
- //GCD请求网络(GET方式测试通过,POST方式测试未通过)
- - (void) gcdHttpRequestWithURL:(NSString *) URLString
- httpMethod:(GCDHelperHttpRequestMethod) method
- params:(NSDictionary *) params
- timeout:(NSTimeInterval) time
- success:(GCDHttpRequestBlock) successBlock
- fail:(GCDHttpRequestBlock) failBlock;
- @end
- #import "GCDHelper.h"
- #import <SystemConfiguration/SystemConfiguration.h>
- #import <sys/socket.h>
- #import <netinet/in.h>
- #import <netinet6/in6.h>
- #import <arpa/inet.h>
- #import <ifaddrs.h>
- #import <netdb.h>
- //Error
- #define GCDHelperErrorURLISNULL [NSError errorWithDomain:@"please setup GCDHelper‘s url or urlString" code:100 userInfo:nil]
- #define GCDHelperErrorRequestISNULL [NSError errorWithDomain:@"request can not be nil!" code:101 userInfo:nil]
- #define GCDHelperErrorFileExist [NSError errorWithDomain:@"File Exist!" code:102 userInfo:nil]
- #define GCDHelperErrorCreateFail [NSError errorWithDomain:@"Create File Fail!" code:103 userInfo:nil]
- //下载的临时文件的后缀
- #define kTHDownLoadTask_TempSuffix @".TempDownload"
- //计算下载速度的取样时间
- #define kTHDownLoadTimerInterval 2.0
- //THDispatchQueue默认的并发数
- #define kTHDispatchQueueDefaultConcurrentCount 10
- #define kDefaultTimeoutInterval 15
- static NSString * const BOUNDRY = @"--------------------------7d71a819230404";
- @implementation GCDHelper
- - (void) dealloc
- {
- [super dealloc];
- }
- - (id) init
- {
- if (self = [super init])
- {
- }
- return self;
- }
- #pragma mark -
- #pragma mark 获取队列
- + (dispatch_queue_t) gcdMainQueue
- {
- return dispatch_get_main_queue();
- }
- + (dispatch_queue_t) gcdGlobalQueue:(GlobalQueuePriority) priority
- {
- switch (priority)
- {
- case GlobalQueuePriorityDefault:
- return dispatch_get_global_queue(priority, 0);
- break;
- case GlobalQueuePriorityHigh:
- return dispatch_get_global_queue(priority, 0);
- break;
- case GlobalQueuePriorityLow:
- return dispatch_get_global_queue(priority, 0);
- break;
- case GlobalQueuePriorityBackground:
- return dispatch_get_global_queue(priority, 0);
- break;
- default:
- return dispatch_get_global_queue(GlobalQueuePriorityDefault, 0);
- break;
- }
- }
- + (dispatch_queue_t) gcdCustomQueue:(NSString *) queueName;
- {
- return dispatch_queue_create([queueName UTF8String], NULL);
- }
- #pragma mark -
- #pragma mark 3种队列上执行Block
- + (void) gcdPerformBlockOnMainQueue:(GCDBlock) block feature:(PerformBlockFeature) feature
- {
- switch (feature)
- {
- case PerformBlockFeatureChoke:
- dispatch_sync([GCDHelper gcdMainQueue], block);
- break;
- case PerformBlockFeatureUnchoke:
- dispatch_async([GCDHelper gcdMainQueue], block);
- break;
- default:
- dispatch_sync([GCDHelper gcdMainQueue], block);
- break;
- }
- }
- + (void) gcdPerformBlockOnGlobalQueue:(GCDBlock) block feature:(PerformBlockFeature) feature priority:(GlobalQueuePriority) priority
- {
- switch (feature)
- {
- case PerformBlockFeatureChoke:
- dispatch_sync([GCDHelper gcdGlobalQueue:priority], block);
- break;
- case PerformBlockFeatureUnchoke:
- dispatch_async([GCDHelper gcdGlobalQueue:priority], block);
- break;
- default:
- dispatch_sync([GCDHelper gcdGlobalQueue:GlobalQueuePriorityDefault], block);
- break;
- }
- }
- + (void) gcdPerformBlockOnCustomQueue:(GCDBlock) block feature:(PerformBlockFeature) feature name:(NSString *) queueName
- {
- switch (feature)
- {
- case PerformBlockFeatureChoke:
- dispatch_sync([GCDHelper gcdCustomQueue:queueName], block);
- break;
- case PerformBlockFeatureUnchoke:
- dispatch_async([GCDHelper gcdCustomQueue:queueName], block);
- break;
- default:
- dispatch_sync([GCDHelper gcdCustomQueue:@"com.GCDHelper.Queue"], block);
- break;
- }
- }
- //后台执行
- + (void) gcdPerformBlockAsynchronous:(GCDBlock) block
- {
- [GCDHelper gcdPerformBlockOnGlobalQueue:block
- feature:PerformBlockFeatureUnchoke
- priority:GlobalQueuePriorityDefault];
- }
- //后台获取数据后,回到主线程
- + (void) gcdPerformBlockAsynchronous:(GCDBlock) blockAsyn
- finishOnMainQueue:(GCDBlock) blockM
- {
- dispatch_async([GCDHelper gcdGlobalQueue:GlobalQueuePriorityDefault], ^{
- blockAsyn();
- dispatch_async([GCDHelper gcdMainQueue], ^{
- blockM();
- });
- });
- }
- #pragma mark -
- #pragma mark 队列延迟时间执行方法
- + (void) gcdPerformBlock:(GCDBlock) block onQueue:(dispatch_queue_t) queue delaySecond:(int64_t) second
- {
- dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, second * NSEC_PER_SEC);
- dispatch_after(popTime, queue, block);
- }
- #pragma mark -
- #pragma mark 只执行一次
- + (void) gcdPerformBlockOnce:(GCDBlock) block
- {
- static dispatch_once_t onceToken;
- dispatch_once(&onceToken, block);
- }
- #pragma mark -
- #pragma mark 无序并发
- + (void) gcdBatchPerformBlocks:(NSArray *) blockArray finally:(GCDBlock) finallyBlock
- {
- [blockArray retain];
- dispatch_queue_t queue = [GCDHelper gcdGlobalQueue:GlobalQueuePriorityDefault];
- dispatch_group_t group = dispatch_group_create();
- for(GCDBlock block in blockArray)
- {
- dispatch_group_async(group, queue, ^{
- block();
- });
- }
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- dispatch_async([GCDHelper gcdGlobalQueue:GlobalQueuePriorityDefault], ^{
- finallyBlock();
- });
- dispatch_release(group);
- [blockArray release];
- }
- + (void) gcdBatchPerformBlockWithData:(NSArray *) dataArray
- maxConcurrentOperationCount:(uint) count
- handleBlock:(GCDBlock1_Obj) block
- finally:(GCDBlock1_Obj) finallyBlock
- {
- [dataArray retain];
- dispatch_queue_t queue = [GCDHelper gcdGlobalQueue:GlobalQueuePriorityDefault];
- dispatch_group_t group = dispatch_group_create();
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(count);
- for(id obj in dataArray)
- {
- NSLog(@"并发中");
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
- dispatch_group_async(group, queue, ^{
- block(obj);
- dispatch_semaphore_signal(semaphore);
- });
- }
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- dispatch_group_notify(group, queue, ^{
- finallyBlock(dataArray);
- });
- dispatch_release(group);
- [dataArray release];
- }
- #pragma mark -
- #pragma mark 图片下载
- - (void) gcdImageWithURLString:(NSString *) URLString
- {
- [self gcdImageWithURLString:URLString completion:nil];
- }
- - (void) gcdImageWithURLString:(NSString *) URLString completion:(GCDBlock2_Obj_Obj) completion
- {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:[NSURL URLWithString:URLString]];
- [request setHTTPMethod:@"GET"];
- NSData *returnData = [NSURLConnection sendSynchronousRequest:request
- returningResponse:nil
- error:nil];
- [request release];
- UIImage *image = [UIImage imageWithData:returnData];
- if (image)
- {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- completion(image, URLString);
- });
- } else
- {
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- completion(image, URLString);
- });
- }
- });
- }
- @end
- #pragma mark -
- #pragma mark 网络部分
- @implementation GCDHelper (NetworkConnect)
- - (BOOL)isReachableWithFlags:(SCNetworkReachabilityFlags)flags
- {
- BOOL connectionUP = YES;
- if(!(flags & kSCNetworkReachabilityFlagsReachable))
- connectionUP = NO;
- if( (flags & (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection)) == (kSCNetworkReachabilityFlagsConnectionRequired | kSCNetworkReachabilityFlagsTransientConnection) )
- connectionUP = NO;
- return connectionUP;
- }
- -(void)reachabilityChanged:(SCNetworkReachabilityFlags)flags
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- _netWorkBlock([self isReachableWithFlags:flags]);
- });
- }
- static void TMReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void* info)
- {
- @autoreleasepool
- {
- [(GCDHelper *)info reachabilityChanged:flags];
- }
- }
- - (void) gcdNetWorkGuarder:(NSString *) hostname withBlock:(GCDBlock1_Bool) block
- {
- _netWorkBlock = block;
- SCNetworkReachabilityRef ref = SCNetworkReachabilityCreateWithName(NULL, [hostname UTF8String]);
- SCNetworkReachabilityContext context = { 0, NULL, NULL, NULL, NULL };
- dispatch_queue_t queue = dispatch_queue_create("com.myself.reachability", NULL);
- context.info = (void *)self;
- SCNetworkReachabilitySetCallback(ref, TMReachabilityCallback, &context);
- SCNetworkReachabilitySetDispatchQueue(ref, queue);
- }
- @end
- @implementation GCDHelper(HttpRequest)
- - (void) startPOSTHTTPRequest:(NSString *) URLString
- params:(NSDictionary *) params
- timeout:(NSTimeInterval) time
- success:(GCDHttpRequestBlock) successBlock
- fail:(GCDHttpRequestBlock) failBlock
- {
- [params retain];
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- __block NSURLResponse *response = nil;
- __block NSError *error = nil;
- __block NSData *receiveData = nil;
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:[NSURL URLWithString:[URLString lowercaseString]]];
- [request setHTTPMethod:@"POST"];
- [request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
- [request setTimeoutInterval:time];
- if (!request)
- {
- NSDictionary *errorInfo = [NSDictionary dictionaryWithObjectsAndKeys:@"发送请求失败", @"errorKey", nil];
- error = [NSError errorWithDomain:@"www.myself.com" code:100 userInfo:errorInfo];
- dispatch_async(dispatch_get_main_queue(), ^{
- successBlock(response, error, receiveData);
- });
- return;
- }
- if (params != nil)
- {
- [request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", BOUNDRY]
- forHTTPHeaderField:@"Content-Type"];
- int len=512;
- NSMutableData *postData =[NSMutableData dataWithCapacity:len];
- [postData appendData:[[NSString stringWithFormat:@"--%@/r/n", BOUNDRY]
- dataUsingEncoding:NSUTF8StringEncoding]];
- int i=0;
- int cnt = [params count];
- for (NSString *key in [params allKeys])
- {
- // NSString *str = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"/r/n/r/n", key];
- [postData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"/r/n/r/n", key] dataUsingEncoding:NSUTF8StringEncoding]];
- [postData appendData: [[NSString stringWithFormat:@"%@",[params objectForKey:key]]
- dataUsingEncoding:NSUTF8StringEncoding]];
- if(i != cnt - 1)
- {
- [postData appendData:[[NSString stringWithFormat:@"/r/n--%@/r/n", BOUNDRY]
- dataUsingEncoding:NSUTF8StringEncoding]];
- }
- i++ ;
- }
- [postData appendData:[[NSString stringWithFormat:@"/r/n--%@--/r/n", BOUNDRY]
- dataUsingEncoding:NSUTF8StringEncoding]];
- [request setHTTPBody:postData];
- }
- receiveData = [[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] retain];
- if (!error)
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- successBlock(response, nil, receiveData);
- });
- }
- else
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- successBlock(response, error, receiveData);
- });
- }
- [request release];
- });
- [params release];
- }
- - (void) startGETHTTPRequest:(NSString *) URLString
- params:(NSDictionary *) params
- timeout:(NSTimeInterval) time
- success:(GCDHttpRequestBlock) successBlock
- fail:(GCDHttpRequestBlock) failBlock
- {
- [params retain];
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
- __block NSURLResponse *response = nil;
- __block NSError *error = nil;
- __block NSData *receiveData = nil;
- NSMutableString *paramsString = [[NSMutableString alloc] init];
- for(NSString *key in params)
- {
- [paramsString appendFormat:@"&%@=%@", key, [params objectForKey:key]];
- }
- NSString *requestString = [[NSString alloc] initWithFormat:@"%@%@", URLString, paramsString];
- NSURL *reqUrl = [[NSURL alloc] initWithString:requestString];
- [paramsString release];
- [requestString release];
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:reqUrl];
- [request setHTTPMethod:@"GET"];
- [request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
- [request setTimeoutInterval:time];
- [reqUrl release];
- if (request)
- {
- receiveData = [[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error] retain];
- }
- if (!error)
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- successBlock(response, nil, receiveData);
- });
- }
- else
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- successBlock(response, error, receiveData);
- });
- }
- [request release];
- });
- [params release];
- }
- - (void) gcdHttpRequestWithURL:(NSString *) URLString
- httpMethod:(GCDHelperHttpRequestMethod) method
- params:(NSDictionary *) params
- timeout:(NSTimeInterval) time
- success:(GCDHttpRequestBlock) successBlock
- fail:(GCDHttpRequestBlock) failBlock
- {
- switch (method)
- {
- case GCDHelperHttpRequestMethodGET:
- {
- [self startGETHTTPRequest:URLString params:params timeout:time success:successBlock fail:failBlock];
- break;
- }
- case GCDHelperHttpRequestMethodPOST:
- {
- [self startPOSTHTTPRequest:URLString params:params timeout:time success:successBlock fail:failBlock];
- break;
- }
- default:
- break;
- }
- }
- @end
用法举例:
一、基本概念举例:
- #import <UIKit/UIKit.h>
- @interface BaseViewController : UIViewController
- {
- IBOutlet UITextField *field1;
- IBOutlet UITextField *field2;
- IBOutlet UITextField *field3;
- IBOutlet UITextField *textField;
- dispatch_queue_t queue;
- }
- - (IBAction) calculate:(id)sender;
- - (IBAction) operationQueue:(id)sender;
- - (IBAction) gcd:(id)sender;
- - (IBAction) notchoke:(id)sender;
- - (IBAction) choke:(id)sender;
- - (IBAction) getUIData:(id)sender;
- - (IBAction)startQueue:(id)sender;
- - (IBAction)suspendQueue:(id)sender;
- - (IBAction)resumeQueue:(id)sender;
- @end
- #import "BaseViewController.h"
- @implementation BaseViewController
- - (void) dealloc
- {
- dispatch_release(queue);
- [super dealloc];
- }
- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
- {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- queue = dispatch_queue_create("sss", NULL);
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- // Do any additional setup after loading the view from its nib.
- }
- - (void) longTask:(id) sender
- {
- NSMutableArray *arr = [NSMutableArray array];
- for (int i = 0; i < 1000; i++) {
- [arr addObject:[NSMutableArray arrayWithObject:@(i)]];
- NSLog(@"longTask:%d", i);
- }
- }
- - (void) longTaskOther:(id) sender
- {
- NSMutableArray *arr = [NSMutableArray array];
- for (int i = 0; i < 10000; i++) {
- [arr addObject:[NSMutableArray arrayWithObject:@(i)]];
- NSLog(@"longTaskOther:%d", i);
- }
- }
- - (IBAction) calculate:(id)sender
- {
- field3.text = [NSString stringWithFormat:@"%f", [field1.text floatValue] - [field2.text floatValue]];
- }
- - (IBAction) operationQueue:(id)sender;
- {
- NSOperationQueue *aqueue = [NSOperationQueue new];
- NSInvocationOperation *operation = [[NSInvocationOperation alloc]
- initWithTarget:self
- selector:@selector(longTask:)
- object:nil];
- NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]
- initWithTarget:self
- selector:@selector(longTaskOther:)
- object:nil];
- [aqueue addOperation:operation];
- [aqueue addOperation:operation1];
- [operation release];
- [operation1 release];
- }
- - (IBAction) gcd:(id)sender //3.192999
- {
- [GCDHelper gcdPerformBlockAsynchronous:^{
- NSMutableArray *arr = [NSMutableArray array];
- for (int i = 0; i < 1000; i++) {
- [arr addObject:[NSMutableArray arrayWithObject:@(i)]];
- NSLog(@"longTask:%d", i);
- }
- }];
- [GCDHelper gcdPerformBlockAsynchronous:^{
- NSMutableArray *arr = [NSMutableArray array];
- for (int i = 0; i < 10000; i++) {
- [arr addObject:[NSMutableArray arrayWithObject:@(i)]];
- NSLog(@"longTaskOther:%d", i);
- }
- }];
- }
- //
- - (IBAction)notchoke:(id)sender
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- NSLog(@"qqq");
- });
- NSLog(@"不阻塞");
- }
- //Calls to dispatch_sync() targeting the current queue will result
- //* in dead-lock. Use of dispatch_sync() is also subject to the same
- //* multi-party dead-lock problems that may result from the use of a mutex.
- //* Use of dispatch_async() is preferred.
- //在当前队列上调用dispatch_sync() 会导致死锁。调用dispatch_sync(),并使用mutex 经常会导致多方死锁问题。
- - (IBAction) choke:(id)sender
- {
- dispatch_queue_t exampleQueue;
- int i = 3;
- switch (i) {
- case 0:
- exampleQueue = dispatch_get_global_queue(0, 0);
- break;
- case 1:
- exampleQueue = dispatch_queue_create("com.abc.xxx", NULL);
- break;
- case 2:
- exampleQueue = dispatch_get_current_queue();
- break;
- case 3:
- exampleQueue = dispatch_get_main_queue();
- break;
- default:
- exampleQueue = dispatch_get_global_queue(0, 0);
- break;
- }
- dispatch_sync( exampleQueue,^{
- [self longTask:nil];
- });
- NSLog(@"task finish");
- }
- - (IBAction) getUIData:(id)sender
- {
- dispatch_async(dispatch_get_global_queue(0, 0), ^{
- __block NSString *stringValue;
- dispatch_sync(dispatch_get_main_queue(), ^{
- stringValue = [textField.text copy];
- });
- [stringValue retain];
- NSLog(@"stringValue:%@", stringValue);
- });
- }
- //一个要注意的地方是,dispatch queue的挂起是block粒度的。换句话说,挂起一个queue并不会将当前正在执行的block挂起。它会允许当前执行的block执行完毕,然后后续的block不再会被执行,直至queue被恢复。
- //还有一个注意点:从man页上得来的:如果你挂起了一个queue或者source,那么销毁它之前,必须先对其进行恢复。
- - (IBAction)startQueue:(id)sender
- {
- dispatch_async(queue, ^{
- for (int i = 0; i < 10000; i++) {
- NSLog(@"taskA");
- }
- });
- dispatch_async(queue, ^{
- for (int i = 0; i < 10000; i++) {
- NSLog(@"taskB");
- }
- });
- dispatch_async(queue, ^{
- for (int i = 0; i < 10000; i++) {
- NSLog(@"taskC");
- }
- });
- }
- - (IBAction)suspendQueue:(id)sender
- {
- NSLog(@"Queue suspend");
- dispatch_suspend(queue);
- }
- - (IBAction)resumeQueue:(id)sender
- {
- NSLog(@"Queue resume");
- dispatch_resume(queue);
- }
二、基本用法举例
例子1:
- #import <UIKit/UIKit.h>
- @interface OneViewController : UIViewController
- //无序并发
- - (IBAction)selector0:(id)sender;
- //无序并发处理数据
- - (IBAction)selector100:(id)sender;
- //执行一次
- - (IBAction)selector1:(id)sender;
- //异步/后台执行
- - (IBAction)selector2:(id)sender;
- //后台执行,然后返回主线程
- - (IBAction)selector3:(id)sender;
- //三种队列执行
- - (IBAction)selector4:(UISegmentedControl *)sender;
- //延迟执行
- - (IBAction)selector5:(id)sender;
- @end
- #import "OneViewController.h"
- @interface OneViewController ()
- @end
- @implementation OneViewController
- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
- {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self) {
- // Custom initialization
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- }
- - (NSMutableArray *) getBlockArray
- {
- NSMutableArray *arr = [[NSMutableArray array] retain];
- GCDBlock b0 = ^{ NSLog(@"无序并发: 0"); sleep(3); }; [arr addObject:b0];
- GCDBlock b1 = ^{ NSLog(@"无序并发: 1"); }; [arr addObject:b1];
- GCDBlock b2 = ^{ NSLog(@"无序并发: 2"); }; [arr addObject:b2];
- GCDBlock b3 = ^{ NSLog(@"无序并发: 3"); }; [arr addObject:b3];
- GCDBlock b4 = ^{ NSLog(@"无序并发: 4"); }; [arr addObject:b4];
- GCDBlock b5 = ^{ NSLog(@"无序并发: 5"); }; [arr addObject:b5];
- GCDBlock b6 = ^{ NSLog(@"无序并发: 6"); }; [arr addObject:b6];
- GCDBlock b7 = ^{ NSLog(@"无序并发: 7"); }; [arr addObject:b7];
- GCDBlock b8 = ^{ NSLog(@"无序并发: 8"); }; [arr addObject:b8];
- GCDBlock b9 = ^{ NSLog(@"无序并发: 9"); }; [arr addObject:b9];
- GCDBlock b10 = ^{ NSLog(@"无序并发: 10"); }; [arr addObject:b10];
- GCDBlock b11 = ^{ NSLog(@"无序并发: 11"); }; [arr addObject:b11];
- GCDBlock b12 = ^{ NSLog(@"无序并发: 12"); }; [arr addObject:b12];
- GCDBlock b13 = ^{ NSLog(@"无序并发: 13"); }; [arr addObject:b13];
- GCDBlock b14 = ^{ NSLog(@"无序并发: 14"); }; [arr addObject:b14];
- GCDBlock b15 = ^{ NSLog(@"无序并发: 15"); }; [arr addObject:b15];
- return arr;
- }
- //无序并发
- - (IBAction)selector0:(id)sender
- {
- [GCDHelper gcdBatchPerformBlocks:[self getBlockArray] finally:^{
- NSLog(@"一组有序并发完成");
- }];
- // NSLog(@"一组无序并发完成");
- }
- - (IBAction)selector100:(id)sender
- {
- NSMutableArray *arr = [NSMutableArray array];
- for (int i = 0; i < 100; i++) {
- [arr addObject:[NSMutableArray array]];
- }
- __block int i = 0;
- [GCDHelper gcdBatchPerformBlockWithData:arr maxConcurrentOperationCount:10 handleBlock:^(id object) {
- sleep(1);
- NSMutableArray *arr = (NSMutableArray *)object;
- [arr addObject:@(i)];
- i++;
- } finally:^(id object) {
- NSLog(@"arr:%@", object);
- }];
- }
- - (IBAction)selector1:(id)sender
- {
- [GCDHelper gcdPerformBlockOnce:^{
- NSLog(@"别想让我执行第二次");
- }];
- NSLog(@"不执行~");
- }
- //异步/后台执行
- - (IBAction)selector2:(id)sender
- {
- [GCDHelper gcdPerformBlockAsynchronous:^{
- sleep(3);
- NSLog(@"全局队列执行完成");
- }];
- NSLog(@"全局队列执行,不影响主队列");
- }
- //后台执行,然后返回主线程
- - (IBAction)selector3:(id)sender
- {
- [GCDHelper gcdPerformBlockAsynchronous:^{
- for (int i = 0; i< 10; i++)
- {
- NSLog(@"全局队列执行: %d", i);
- }
- } finishOnMainQueue:^{
- NSLog(@"回到主队列");
- }];
- }
- //三种队列执行
- - (IBAction)selector4:(UISegmentedControl *)sender
- {
- switch (sender.selectedSegmentIndex) {
- case 0:
- {
- [GCDHelper gcdPerformBlockOnMainQueue:^{
- NSLog(@"主队列执行");
- } feature:PerformBlockFeatureUnchoke];
- break;
- }
- case 1:
- {
- [GCDHelper gcdPerformBlockOnGlobalQueue:^{
- NSLog(@"全局队列执行");
- } feature:PerformBlockFeatureUnchoke priority:GlobalQueuePriorityDefault];
- break;
- }
- case 2:
- {
- [GCDHelper gcdPerformBlockOnCustomQueue:^{
- NSLog(@"自创建队列执行");
- } feature:PerformBlockFeatureUnchoke name:@"com.abc.bcd"];
- break;
- }
- default:
- break;
- }
- }
- //延迟执行
- - (IBAction)selector5:(id)sender
- {
- NSLog(@"延迟 2s 执行");
- [GCDHelper gcdPerformBlock:^{
- NSLog(@"执行完毕");
- } onQueue:[GCDHelper gcdMainQueue] delaySecond:2];
- }
- @end
例子2:
- #import <UIKit/UIKit.h>
- @interface MulthreadConcurrentVC : UIViewController
- @end
- #import "MulthreadConcurrentVC.h"
- /*
- 如何在GCD中快速的控制并发呢?答案就是
- dispatch_semaphore,对经常做unix开发的人来讲,我所介绍的内容可能就显得非常入门级了,信号量在他们的多线程开发中再平常不过了。
- 在GCD中有三个函数是semaphore的操作,分别是:
- dispatch_semaphore_create 创建一个semaphore
- dispatch_semaphore_signal 发送一个信号
- dispatch_semaphore_wait 等待信号
- 简单的介绍一下这三个函数,第一个函数有一个整形的参数,我们可以理解为信号的总量,dispatch_semaphore_signal是发送一个信号,自然会让信号总量加1,dispatch_semaphore_wait等待信号,当信号总量少于0的时候就会一直等待,否则就可以正常的执行,并让信号总量减少1,根据这样的原理,我们便可以快速的创建一个并发控制。
- */
- /*
- 简单的介绍一下这一段代码,创建了一个初使值为10的semaphore,每一次for循环都会创建一个新的线程,线程结束的时候会发送一个信号,线程创建之前会信号等待,所以当同时创建了10个线程之后,for循环就会阻塞,等待有线程结束之后会增加一个信号才继续执行,如此就形成了对并发的控制,如上就是一个并发数为10的一个线程队列。
- */
- @implementation MulthreadConcurrentVC
- - (void) loadView
- {
- [super loadView];
- }
- - (void)aSelector:(id)sender
- {
- dispatch_group_t group = dispatch_group_create();
- dispatch_semaphore_t semaphore = dispatch_semaphore_create(10);
- dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
- for (int i = 0; i < 100; i++)
- {
- dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
- dispatch_group_async(group, queue, ^{
- NSLog(@"%i",i);
- sleep(2);
- dispatch_semaphore_signal(semaphore);
- });
- }
- dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
- dispatch_release(group);
- dispatch_release(semaphore);
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- UIButton *bt = [UIButton buttonWithType:UIButtonTypeRoundedRect];
- bt.frame = CGRectMake(100, 100, 120, 120);
- [bt addTarget:self action:@selector(aSelector:) forControlEvents:UIControlEventTouchUpInside];
- [self.view addSubview:bt];
- }
三、GCD实际应用举例
- #import <UIKit/UIKit.h>
- #import "GCDHelper.h"
- @interface TableViewController : UITableViewController
- @end
- #import "TableViewController.h"
- #import "CustomCell.h"
- #import <objc/runtime.h>
- static char * const kIndexPathAssociationKey = "JK_indexPath";
- @interface TableViewController ()
- @end
- @implementation TableViewController
- - (id)initWithStyle:(UITableViewStyle)style
- {
- self = [super initWithStyle:style];
- if (self) {
- // Custom initialization
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- self.clearsSelectionOnViewWillAppear = NO;
- self.navigationItem.rightBarButtonItem = self.editButtonItem;
- }
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- #pragma mark - Table view data source
- - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
- {
- return 1;
- }
- - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
- {
- return 100;
- }
- - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- {
- static NSString *CellIdentifier = @"Cell";
- UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
- if (cell == nil) {
- cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
- UIImageView *im = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 40)];
- im.tag = 10;
- [cell addSubview:im];
- [im release];
- }
- return cell;
- }
- - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
- {
- // http://localhost:8888/Imgs/img0.png
- // http://theme.blogcn.com/wp-content/themes/coffee-desk/images/rsscoffee.PNG
- NSString *imgURLStr = nil;
- if ((indexPath.row % 2) == 0)
- {
- imgURLStr = @"http://localhost:8888/Imgs/img0.png";
- } else
- {
- imgURLStr = @"http://localhost:8888/Imgs/img1.png";
- }
- GCDHelper *hp = [GCDHelper new];
- [hp gcdImageWithURLString:imgURLStr
- completion:^(id object1, id object2) {
- dispatch_async(dispatch_get_main_queue(), ^{
- UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
- [(UIImageView *)[cell viewWithTag:10] setImage:(UIImage *)object1];
- });
- }];
- }
- #pragma mark - Table view delegate
- - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
- {
- }
- #pragma mark -
- #pragma mark - cell重用
- - (void)tableViewCellIsPreparingForReuse:(NSNotification *)notification
- {
- if ([[notification object] isKindOfClass:[CustomCell class]]) {
- CustomCell *cell = (CustomCell *)[notification object];
- objc_setAssociatedObject(cell,
- kIndexPathAssociationKey,
- nil,
- OBJC_ASSOCIATION_RETAIN);
- [[cell imageView] setImage:nil];
- }
- }
- @end
- #import <UIKit/UIKit.h>
- extern NSString * const kJKPrepareForReuseNotification;
- @interface CustomCell : UITableViewCell
- @end
- #import "CustomCell.h"
- NSString * const kJKPrepareForReuseNotification = @"JKCallbacksTableViewCell_PrepareForReuse";
- @implementation CustomCell
- - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
- {
- self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
- if (self) {
- //如果cell 的图片发生改变,当cell重用的时候,刷新图片
- [[self imageView] addObserver:self
- forKeyPath:@"image"
- options:NSKeyValueObservingOptionOld
- context:NULL];
- }
- return self;
- }
- - (void)observeValueForKeyPath:(NSString *)keyPath
- ofObject:(id)object
- change:(NSDictionary *)change
- context:(void *)context
- {
- NSLog(@"observeValueForKeyPath");
- if (object == [self imageView] &&
- [keyPath isEqualToString:@"image"] &&
- ([change objectForKey:NSKeyValueChangeOldKey] == nil ||
- [change objectForKey:NSKeyValueChangeOldKey] == [NSNull null]))
- {
- [self setNeedsLayout];
- }
- }
- - (void)prepareForReuse
- {
- [[NSNotificationCenter defaultCenter] postNotificationName:kJKPrepareForReuseNotification
- object:self];
- [super prepareForReuse];
- }
- @end
----------------------------------------------
- #import <Foundation/Foundation.h>
- @interface NetGuarder : NSObject
- + (NetGuarder *) shareNetGuarder;
- @end
- #import "NetGuarder.h"
- @implementation NetGuarder
- static NetGuarder *guarder = nil;
- + (void) getNetConnectMsg
- {
- GCDHelper *hp = [GCDHelper new];
- [hp gcdNetWorkGuarder:@"www.baidu.com" withBlock:^(BOOL flag) {
- if (flag)
- {
- NSLog(@"Net connect");
- } else
- {
- NSLog(@"Net not connect");
- }
- }];
- }
- + (NetGuarder *) shareNetGuarder
- {
- static dispatch_once_t predicate;
- dispatch_once(&predicate, ^{
- NSLog(@"单例创建");
- guarder = [[self alloc] init];
- [NetGuarder getNetConnectMsg];
- });
- return guarder;
- }
- @end
-------------------------------------------
- #import <UIKit/UIKit.h>
- @interface URLConViewController : UIViewController <NSURLConnectionDataDelegate>
- {
- IBOutlet UISegmentedControl *segment;
- IBOutlet UILabel *label;
- }
- @end
- #import "URLConViewController.h"
- typedef struct _INT
- {
- int t1;
- }INT_STRUCT;
- @interface URLConViewController ()
- {
- NSMutableData *receivedData;
- BOOL finished;
- }
- @end
- @implementation URLConViewController
- - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
- {
- self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
- if (self)
- {
- receivedData = [[NSMutableData data] retain];
- }
- return self;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- }
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- }
- - (void) cleanText
- {
- label.text = @"";
- }
- - (IBAction)segmentAction:(UISegmentedControl *)sender
- {
- switch (sender.selectedSegmentIndex) {
- case 0:
- {
- [self sendRequestSync];
- break;
- }
- case 1:
- {
- [self sendRequestAsync];
- break;
- }
- case 2:
- {
- [self sendRequestAsyncOther];
- break;
- }
- case 3:
- {
- [self gcdRequest];
- break;
- }
- default:
- break;
- }
- }
- #pragma mark -
- #pragma mark GCDRequest
- - (void) gcdRequest
- {
- GCDHelper *hp = [GCDHelper new];
- [hp gcdHttpRequestWithURL:@"http://localhost:8888/test.php"
- httpMethod:GCDHelperHttpRequestMethodGET
- params:[NSDictionary dictionary]
- timeout:5.0f
- success:^(NSURLResponse *response, NSError *error, NSData *data) {
- if (data && (!error))
- {
- label.text = [[data objectFromJSONData] description];
- }
- }
- fail:^(NSURLResponse *response, NSError *error, NSData *data) {
- if (error)
- {
- label.text = [error description];
- }
- }];
- }
- #pragma mark -
- #pragma mark sendRequestSync
- - (void) sendRequestSync
- {
- [self cleanText];
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:[NSURL URLWithString:@"http://localhost:8888/test.php"]];
- [request setHTTPMethod:@"GET"];
- NSError *error = nil;
- NSData *data = [NSURLConnection sendSynchronousRequest:request
- returningResponse:nil
- error:&error];
- if (data && (!error))
- {
- label.text = [[data objectFromJSONData] description];
- }
- }
- #pragma mark -
- #pragma mark sendRequestAsync
- - (void) sendRequestAsync
- {
- finished = NO;
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:[NSURL URLWithString:@"http://localhost:8888/test1.php"]];
- [request setHTTPMethod:@"GET"];
- [request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
- [request setTimeoutInterval:5.0f];
- NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request
- delegate:self
- startImmediately:YES];
- [connection start];
- // 但是异步模式下带来了一个新的问题,很多情况下,网络请求不在主线程,或者界面等待网络结果,不在主线程的时候,调用线程如果生命周期over,下面这些可能都没有调用到,导致得不到想要得效果,所以需要在NSURLConnection请求后面加点东西来阻塞
- while(!finished) {
- [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
- }
- }
- // 收到回应
- - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
- {
- // 注意这里将NSURLResponse对象转换成NSHTTPURLResponse对象才能去
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
- if ([response respondsToSelector:@selector(allHeaderFields)])
- {
- NSDictionary *dictionary = [httpResponse allHeaderFields];
- NSLog(@"allHeaderFields: %@",dictionary);
- }
- [receivedData setLength:0];
- }
- // 接收数据
- - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
- {
- NSLog(@"get some data");
- [receivedData appendData:data];
- }
- // 数据接收完毕
- - (void)connectionDidFinishLoading:(NSURLConnection *)connection
- {
- NSString *results = [[NSString alloc] initWithBytes:[receivedData bytes]
- length:[receivedData length]
- encoding:NSUTF8StringEncoding];
- label.text = [[results objectFromJSONString] description];
- finished = YES;
- }
- // 返回错误
- -(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
- {
- NSLog(@"Connection failed: %@", error);
- }
- #pragma mark -
- #pragma mark sendRequestAsyncOther
- - (IBAction) sendRequestAsyncOther
- {
- [self cleanText];
- NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
- [request setURL:[NSURL URLWithString:@"http://localhost:8888/test2.php"]];
- [request setHTTPMethod:@"GET"];
- [request setCachePolicy:NSURLRequestUseProtocolCachePolicy];
- [request setTimeoutInterval:5.0f];
- [NSURLConnection sendAsynchronousRequest:request
- queue:[NSOperationQueue new]
- completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
- dispatch_async(dispatch_get_main_queue(), ^{
- label.text = [[data objectFromJSONData] description];
- });
- }];
- }
- @end
----------------------------------------------
- #import <Foundation/Foundation.h>
- /** Simple GCD-based timer based on NSTimer.
- Starts immediately and stops when deallocated. This avoids many of the typical problems with NSTimer:
- * RNTimer runs in all modes (unlike NSTimer)
- * RNTimer runs when there is no runloop (unlike NSTimer)
- * Repeating RNTimers can easily avoid retain loops (unlike NSTimer)
- */
- @interface RNTimer : NSObject
- /**---------------------------------------------------------------------------------------
- @name Creating a Timer
- -----------------------------------------------------------------------------------------
- */
- /** Creates and returns a new repeating RNTimer object and starts running it
- After `seconds` seconds have elapsed, the timer fires, executing the block.
- You will generally need to use a weakSelf pointer to avoid a retain loop.
- The timer is attached to the main GCD queue.
- @param seconds The number of seconds between firings of the timer. Must be greater than 0.
- @param block Block to execute. Must be non-nil
- @return A new RNTimer object, configured according to the specified parameters.
- */
- + (RNTimer *)repeatingTimerWithTimeInterval:(NSTimeInterval)seconds block:(dispatch_block_t)block;
- /**---------------------------------------------------------------------------------------
- @name Firing a Timer
- -----------------------------------------------------------------------------------------
- */
- /** Causes the block to be executed.
- This does not modify the timer. It will still fire on schedule.
- */
- - (void)fire;
- /**---------------------------------------------------------------------------------------
- @name Stopping a Timer
- -----------------------------------------------------------------------------------------
- */
- /** Stops the receiver from ever firing again
- Once invalidated, a timer cannot be reused.
- */
- - (void)invalidate;
- @end
- #import "RNTimer.h"
- @interface RNTimer ()
- @property (nonatomic, readwrite, copy) dispatch_block_t block;
- @property (nonatomic, readwrite, assign) dispatch_source_t source;
- @end
- @implementation RNTimer
- @synthesize block = _block;
- @synthesize source = _source;
- + (RNTimer *)repeatingTimerWithTimeInterval:(NSTimeInterval)seconds
- block:(void (^)(void))block {
- NSParameterAssert(seconds);
- NSParameterAssert(block);
- RNTimer *timer = [[self alloc] init];
- timer.block = block;
- timer.source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER,
- 0, 0,
- dispatch_get_main_queue());
- uint64_t nsec = (uint64_t)(seconds * NSEC_PER_SEC);
- dispatch_source_set_timer(timer.source,
- dispatch_time(DISPATCH_TIME_NOW, nsec),
- nsec, 0);
- dispatch_source_set_event_handler(timer.source, block);
- dispatch_resume(timer.source);
- return timer;
- }
- - (void)invalidate {
- if (self.source) {
- dispatch_source_cancel(self.source);
- dispatch_release(self.source);
- self.source = nil;
- }
- self.block = nil;
- }
- - (void)dealloc {
- [self invalidate];
- }
- - (void)fire {
- self.block();
- }
- @end