简介:
Block是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性。
用Apple文档的话来说,A block is an anonymous inline collection of code, and sometimes also called a “closure”.
1. block的定义形式
返回值 (^block的名称)(参数类型,参数类型.……)= ^(参数列表 ){
//doSomething;
};
2. block的分类
根据Block中是否引用了自动变量,可以将Block存储区域分类:
- _NSConcreteGlobalBlock-存储在全局数据区域(和全局变量一样)
- _NSConcreteStackBlock-存储在栈上
- _NSConcreteMallocBlock-存储在堆上
1). _NSConcreteGlobalBlock
BLOCK代码块不使用局部变量,使用globle变量,或者static变量
int main(){
@autoreleasepool{
void (^test)() = ^(){
NSLog(@"%@",@"testblock");
};
NSLog(@"%@",test);// 打印出 <__NSGlobalBlock__: 0x10c8da050>
}
return 0 ;
}
2). _NSConcreteStackBlock
BLOCK代码块使用局部变量时
int main(){
@autoreleasepool{
int a = 1;
void (^test)() = ^(){
NSLog(@"%@%d",@"testblock",a);
}; //MRC环境,在ARC环境返回MallocBlock
NSLog(@"%@",test);// 打印出 <__NSStackBlock__: 0x7fff563f2ba8>
}
return 0 ;
}
3). _NSConcreteMallocBlock
int main(){
@autoreleasepool{
int a = 1;
void (^test)() = [^(){
NSLog(@"%@%d",@"testblock",a);
}copy];
NSLog(@"%@",test); //打印 <__NSMallocBlock__: 0x7fab13d02a90>
}
return 0 ;
}
3 变量读取与修改(ARC环境)
3.1 基本数据类型
3.1.1 全局变量
修改不需要__block修饰
3.1.2 静态变量
修改不需要__block修饰
3.1.3 局部变量
修改需要__block修饰
3.2 对象
3.2.1 全局指针变量
可以直接修改指针值,block_copy()不增加全局变量的引用计数
NSString *str;//全局变量
-(void)bb{
str = [[NSString alloc] initWithFormat:@"aa"];
void (^test)() = ^(){
NSLog(@"%@",str);//不增加引用计数
};
test();//打印出 aa,str的引用计数为1
str = nil;
test();//打印出 (null)
return;
}
3.2.2 静态指针变量
可以直接修改指针值,block_copy()不增加全局变量的引用计数,同3.2.1.
3.2.3 局部指针变量
不用__block,__weak修饰,
-(id)bb{
NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
void (^test)() = ^(){
NSLog(@"%@",str);
};
test();//打印 aa
str = nil;
test();//打印 aa
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];
test();//打印 aa
}
多个变量指向同一对象的引用计数
-(id)bb{
NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
NSString *str1 = str;
void (^test)() = ^(){
NSLog(@"%@",str);//引用计数+1
NSLog(@"%@",str1);//引用计数+1
};
test();//打印 aa
str = nil;
test();//打印 aa
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];
test();//打印 aa ,同时str的retainCount=2
}
__block修饰
__block修饰的对象在栈展开后才对外部变量增加引用计数。看代码,
-(id)bb{
__block NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
void (^test)() = ^(){
NSLog(@"%@",str);//未增加引用计数
};
test();//打印 aa
str = nil;
test();//打印(null)
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];//展开后才对外部引用对象增加引用计数
test();//打印(null)
}
-(id)bb{
__block NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
void (^test)() = ^(){
NSLog(@"%@",str);
};
test();//打印 aa
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];
test();//打印 aa
}
__weak修饰
-(id)bb{
NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
__weak NSString *wStr = str;
void (^test)() = ^(){
NSLog(@"%@",wStr);//不增加引用计数
};
test();
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];
test();//打印(null)
}
Weak-Strong Dance 避免循环引用,并保证代码执行一致
-(id)bb{
NSString *str;
str = [[NSString alloc] initWithFormat:@"aa"];
__weak NSString *wStr = str;
void (^test)() = ^(){
NSString *ss = wStr;//block_copy()时不增加引用计数,执行时如果 wStr!=nil,则会强引用该对象,防止在多线程环境下,代码执行一半时,对象被释放,导致结果出错。
if (ss){
NSLog(@"%@",ss);
NSLog(@"%@",ss);
}
};
test();
return test;
}
- (void)viewDidLoad {
[super viewDidLoad];
void (^test)() = [self bb];
test();//打印(null)
}
参考
http://my.oschina.net/leejan97/blog/268536
http://www.cnblogs.com/biosli/archive/2013/05/29/iOS_Objective-C_Block.html
http://www.cocoachina.com/ios/20150109/10891.html