// main.m
// 块的使用
#import <Foundation/Foundation.h>
#include <stdlib.h>
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<ArrayElements; elem++) {
unsigned int value = arc4random() % 100;
[numbers addObject:[NSNumber numberWithUnsignedInt:value]];
}
NSLog(@ "Values:%@" , numbers); //记录未排序的数值
//以升序方式为数组数值排序
[numbers sortUsingComparator:^(id obj1, id obj2){
if ([obj1 integerValue] > [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;
}
|