实现代码:
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
完整的项目链接:http://pan.baidu.com/share/link?shareid=386371&uk=3674861929
转载请保留,原文链接:http://write.blog.csdn.net/postedit/8708667
若发现有不合适或错误之处,还请批评指正,不胜感激。