Block:
// main.m// 块的使用#import#include typedef void (^DownloadURL)(void);//获取用于下载URL的块DownloadURL getDownloadURLBlock(NSString *url){ NSString *urlString = url; return ^{ //下载URL NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]]; NSError *error; NSDate *startTime = [NSDate date]; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error]; if (data == nil) { NSLog(@"Error loading request %@", [error localizedDescription]); } else { NSDate *endTime = [NSDate date]; NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime]; NSLog(@"Time taken to download %@ = %f seconds", urlString, timeInterval); } };}int main(int argc, const char * argv[]) { @autoreleasepool { //block可以理解为闭包或者lambda也可以是函数指针 也可以是匿名内部类 #pragma mark - 块的定义 /*定义块的语法格式如下: ^[块返回值类型] (形参类型1 形参1,形参类型2 形参2, ...){ //块执行体 } */ //定义不带参数、无返回值的块 void (^printStr) (void) = ^(void){ NSLog(@"这是块"); }; //使用printStr调用块 printStr(); //定义带参数、有返回值的块 double (^hypot) (double ,double) = ^(double num1 ,double num2){ return sqrt(num1 * num1 + num2 * num2); }; //调用块,并输出块的返回值 NSLog(@"%g" , hypot(3,4)); //也可以先只定义块变量:定义带参数、无返回值的快 void (^print) (NSString *); //再将块赋值给指定的块变量 print = ^(NSString * info){ NSLog(@"info参数为:%@" , info); }; //调用块 print(@"测试块调用"); #pragma mark - 修改局部变量的值 /*块可以访问程序中局部变量的值,当块访问局部变量的值时,不允许修改局部变量的值 如果不希望在定义块时就把局部变量的值复制到块中,而是等到执行时才去访问、获取局部变量的值, 甚至希望块也可以改变局部变量的值,此时可以考虑使用__block修饰局部变量。*/ //定义__block修饰的全局变量 //int one = 1; __block int my = 20; void (^printMy)(void) = ^(void){ //运行时访问、获取局部变量的值,此处输出45 NSLog(@"%d" , my); //尝试对_block局部变量赋值是允许的 my = 30; //one = 2; //Xcode会提示无法对one进行修改,除非用__block进行了修饰 //此处输出30 NSLog(@"%d" , my); }; my = 45; printMy();//调用块 //由于块修改了__block局部变量的值,因此下面的代码输出30 NSLog(@"块执行完后,my的值为:%d" , my); #pragma mark - 使用typedef定义块类型 /*使用typedef定义块类型的语法格式如下: typedef 块返回值类型 (^块类型) (形参类型1 [形参名] ,形参类型2 [形参名] , ... ); */ /*使用typedef可以定义块类型,定义了块类型后,该块类型主要有如下两个用途: 1.复用块类型,使用块类型可以重复定义多个块变量。 2.使用块类型定义函数参数,这样即可定义带块参数的函数。*/ //使用typedef定义块类型 typedef void (^FKPrintBlock) (NSString*); //使用FKPrintBlock定义块变量,并将指定块赋给该变量 FKPrintBlock printt = ^(NSString * info){ NSLog(@"%@" , info); }; //使用FKPrintBlock定义块变量,并将指定块赋值给该变量 FKPrintBlock loopPrint = ^(NSString * info){ for (int i = 0 ; i < 2 ; i++){ NSLog(@"%@" , info); } }; //一次调用两个块 printt(@"Objective-C"); loopPrint(@"iOS"); #pragma mark - 作为方法的参数 /*作为方法声明的参数 //- (void)方法名:(返回值类型 (^)(参数类型))block的名称; - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName; */ NSArray *jingse = @[@"锦瑟无端五十弦,",@"一弦一柱思华年。",@"庄生晓梦迷蝴蝶,",@"望帝春心托杜鹃。",@"沧海月明珠有泪,",@"蓝田日暖玉生烟",@1,@NO]; //定义一个block块操作 return(^fpointer)(int,NS*...) = ^(int a,NS* B...){...}; void (^Pblock1)(id,NSUInteger,BOOL*) = ^(id obj,NSUInteger idx,BOOL *stop){ NSLog(@"%ld --> %@",idx,obj); if (idx == [jingse count]) { *stop = YES; } }; //匿名block指针 [jingse enumerateObjectsUsingBlock:Pblock1]; //- (void)enumerateObjectsUsingBlock:(void (^)(ObjectType obj, NSUInteger idx, BOOL *stop)); //?????// BOOL *stop = NO;// for (int i = 0 ; stop; i++)// Pblock1(jingse[i],i,stop); #pragma mark - 块的内存管理 /*1)在运行程序时,块常量表达式会获得栈内存,因而会拥有与局部变量相同的生命周期。 因此,它们您必须被复制到永久存储区域(即堆)中,才能在定义它们的范围之外使用。 2)使用Block_copy()命令可以将块常量复制到堆中,使用Block_release()命令可以释放堆中的块常量. 3)在使用ARC时,只要块没有返回id类型值或将id类型值用作参数,编译器就会自动执行块的复制和释放操作。否则,就必须手动执行复制和释放操作。 4)在使用MRR时,__block变量不会被保留;而在使用ARC时,__block变量会被保留。这就意味着如果你在使用ARC时不想不想保留__block变量(如避免循环引用),还应对变量应用__weak存储类型修饰符*/ /*在MRR下使用 void (^greetingBlock)(void) { greetingBlock = [^{ NSLog(@"Hello Jabit"); } copy]; } greetingBlock(); [greetingBlock release];*/ /*在MRR下使用 void (^greetingBlock)(id salutation); { greetingBlock = Block_copy(^(id salutation){ NSLog(@"%@, Jabit", salutation); }); } greetingBlock(@"Hello"); Block_release(greetingBlock);*/ #pragma mark - 在OC中使用block /*1、作为变量 //1 返回值类型 (^block的名称)(参数类型) = ^返回值类型(参数) {...}; //2 returnType (^blockName)(parameterTypes) = ^returnType(parameters) {...}; 2、作为属性 //1 @property (nonatomic, copy) 返回值类型 (^block的名称)(参数类型); //2 @property (nonatomic, copy) returnType (^blockName)(parameterTypes); 3、作为方法声明的参数 //1 - (void)方法名:(返回值类型 (^)(参数类型))block的名称; //2 - (void)someMethodThatTakesABlock:(returnType (^)(parameterTypes))blockName; 4、作为方法实现的参数 //1 [对象/类 方法名:^返回值类型 (参数) {...}]; //2 [someObject someMethodThatTakesABlock:^returnType (parameters) {...}]; 5、使用typedef定义块类型 */ #pragma mark - 使用块为数组排序#define ArrayElements 10 //创建一个含有随机数值(0~99)的数组 NSMutableArray *numbers = [NSMutableArray arrayWithCapacity:ArrayElements]; for (int elem=0; elem [obj2 integerValue]) { return (NSComparisonResult)NSOrderedDescending; } if ([obj1 integerValue] < [obj2 integerValue]) { return (NSComparisonResult)NSOrderedAscending; } return (NSComparisonResult)NSOrderedSame; }]; NSLog(@"Values:%@", numbers); //记录已排序的数值 #pragma mark - 使用块加载URL#define IndexURL @"http://www.wikipedia.com/index.html" //为连接获取当前的运行循环 NSRunLoop *loop = [NSRunLoop currentRunLoop]; BOOL __block downloadComplete = NO; //创建请求 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:IndexURL]]; [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error){ if (data == nil) { NSLog(@"Error loading request %@", [error localizedDescription]); } else { NSLog(@"\n\tDownloaded %lu bytes from request %@\n", [data length], [request URL]); } downloadComplete = YES; }]; //一直循环直到完成加载资源的操作为止(它会运行循环,接收输入源的事件,并执行所有相应的委托或回调方法,直到连接完成加载资源的操作为止 while (!downloadComplete && [loop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]); #pragma mark - 使用块的并行编程方式#define YahooURL @"http://www.yahoo.com/index.html"#define ApressURL @"http://www.apress.com/index.html" //创建任务请求(GCD API) dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //创建任务分组 dispatch_group_t group = dispatch_group_create(); //获取度量的当前时间 NSDate *startTime = [NSDate date]; //创建并分派异步任务 dispatch_group_async(group, queue1, getDownloadURLBlock(YahooURL)); dispatch_group_async(group, queue2, getDownloadURLBlock(ApressURL)); //使主进程等待,直到分组中的所有任务完成为止 dispatch_group_wait(group, DISPATCH_TIME_FOREVER); //为并行操作和日志检索时间信息 NSDate *endTime = [NSDate date]; NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime]; NSLog(@"Time taken to download URLs concurrently = %f seconds\n", timeInterval); } return 0;}