标签:
Block简介
1.Block类似于函数,指向一块代码的指针(类似C中的回调函数)Block经常用来代替delegate
2.跟函数的写法基本是一致的 声明 + 实现 + 调用
2.1声明:^ 脱字符
返回类型(^Block的名字)(类型1 参数1,类型2 参数2……);
2.2 实现:Block的名字 = ^(类型1 参数1……){ }
2.3 调用:如果不调用,那么代码块中的内容是不会执行的,什么时候调用,就什么时候执行
Block的名字(参数1,参数2……);
Block基本用法
1.无返回值无参数的block
实现的简写:
eatBlock = ^{
NSLog(@"我在chiFan");
};
void (^eatBlock)();
eatBlock = ^(){
NSLog(@"我在chiFan");
};
eatBlock();
2.有参数无返回值的:写一个block输出a+b的值
void(^sumBlock)(NSInteger a,NSInteger b);
sumBlock = ^(NSInteger a,NSInteger b){
NSLog(@"%d + %d的值为%d",a,b,a+b);
};
sumBlock(20,30);
2.1 简写:声明+实现二合一,并且声明时参数的名字可省略
void(^sumBlock1)(NSInteger,NSInteger) = ^(NSInteger a,NSInteger b) {
NSLog(@"%d + %d的值为%d",a,b,a+b);
};
sumBlock1(50,60);
3.有参数有返回值的block:写一个block用来求a+b的值并且把结果返回
NSInteger (^sumBlock2)(NSInteger,NSInteger) = ^(NSInteger a,NSInteger b) {
return a+b;
};
NSInteger a = sumBlock2(100,200);
NSLog(@"求和的结果为%d",a);
4.通过block修改外部变量的值
结论:
4.1 block内部不能修改block外部的局部变量.如果说非得改,声明时需要加上__block
4.2 全局变量/静态变量可以修改
4.3 block内部可以使用block外部的变量
__block int num = 10;
void (^block1)() = ^(){
int a = num;
num = 20;
};
block1();
5.结论
5.1 如果不用__block修饰变量,block内部使用的是对象的值
5.2 block内部使用的值并不是a的123,它自己重新声明了一个变量b,b内容为123,将来a改变的时候,b并不会改变
5.3 需要加上__block,通过__block的修饰,block内部使用的不再是变量a的值123,而是a的指针(a本身)
__block int sumNum = 123;
void (^block2)() = ^ {
NSLog(@"%d",sumNum);
};
sumNum = 456;
block2();
6. block可以当做属性来用
结论
6.1 声明属性只能用copy修饰
6.2 造成循环引用
self.propertyBlock = ^{
};
7.通过typedef来简化block的定义,一般来说用于简化属性的block
typedef:定义类型
#define:宏定义
MyInt age = 30;
MyBlock block3 = ^{
};
MyBlock block4 = ^{
};
8.block的快捷键
inlineblock
MyNewBlock aBlock = ^(int a,int b) {
NSLog(@"aaaa");
return a+b;
};
aBlock(10,20);
Block内存管理
1.内存主要分五块
1.1 栈(区):由编译器自动分配/释放,一般用来存放函数的参数值,局部变量的值等。
例子:int a = 29;
1.2 堆(区):一般由程序员分配/释放。如果说程序员不释放,程序结束时可能有OS回收
例子:People *p = [[People alloc] init];
1.3 全局区(静态区):全局变量/静态变量放在这个区域。初始化的全局变量/静态变量放在一个区域,未初始化的全局变量/静态变量放在另一个区域。程序结束后由系统释放。
1.4 文字常量区:常量字符串,程序结束后系统释放 NSString *string = @“张三”;
1.5 程序代码区:存放函数体的二进制码
2.Block本身的内存管理
2.1MRC
2.1.1 在MRC下,Block默认分配在“栈区”,如果离开Block所在的作用域,Block会被丢弃/释放
2.1.2 NSGlobalBlock(如果块中没有使用外部变量):对于retain,release,copy无效
NSStackBlock(如果块中使用了外部变量):retain,release无效,copy有效,会得到NSMallocBlock
陷阱:如果把block添加到数组中,然后再从数组中取出的话,如果数组是自动释放的,那么在数组释放的时候里面的所有的对象都会被release
正确:[array addObject:[[block2 copy] autorelease]];
NSMallocBlock(NSStackBlock被copy):支持retain, release.retain/release可以增加/减少引用计数,但是block的retainCount始终为1.
建议:不要对block使用retain操作,不方便管理
2.2 ARC
3.block块中对象的内存
前提:主要是针对copy的block
代码:
__block int a = 10;
void(^block1)() = ^() {
a = 20;
};
block1();
NSLog(@"%@",[block1 copy]);
//陷阱
int b = 20;
MyBlock block2 = ^() {
NSLog(@"%d",b);
};
block2();
NSLog(@"block2:%@",block2);
NSMutableArray *array = [NSMutableArray array];
[array addObject:[[block2 copy] autorelease]];
MyBlock block3 = array[0];
block3();
NSLog(@"block3:%@",block3);
MyBlock block4 = [block3 retain];
NSLog(@"----%d",[block3 retainCount]);
__block People * localObj = [People new];
staticObj = [People new];
gloabObj = [People new];
_propertyObj = [People new];
NSLog(@"%d--%d--%d--%d====%d",localObj.retainCount,staticObj.retainCount,gloabObj.retainCount,_propertyObj.retainCount,self.retainCount);
/*block块中的对象
全局变量:不变
局部变量:通过block copy会+1 (MRC下局部变量一般需要加上__block,防止循环引用,ARC下加__weak)
static变量:不变
属性:不变
self本身也会+1
*/
MyBlock block5 = ^() {
gloabObj.age = 10;
staticObj.age = 20;
_propertyObj.age = 30;
localObj.age = 40;
};
block5();
[block5 copy];
NSLog(@"%d--%d--%d--%d====%d",localObj.retainCount,staticObj.retainCount,gloabObj.retainCount,_propertyObj.retainCount,self.retainCount);
Block导致循环引用的处理方法
Block导致的循环引用:针对于copy后的Block
1.Block内部使用self
1)Block内部使用self,会对self的引用计数+1
2)Block会在dealloc中释放,dealloc方法会在self释放的时候调用(self引用计数+1,dealloc方法是不会被调用)
解决办法:__block MainVC *newVC = self;
2.Block中使用全局变量也会导致循环引用
解决办法:__block NSString *newName = name;
总结:
1.Block属性中不能使用全局变量/属性,一般都转换为用__block修饰的局部变量
2.如果是局部Block,无所谓
NSTimer导致的循环引用
解决办法:在viewDidDisappear关闭定时器
代理导致的循环引用
解决办法:delegate用assign修饰
标签:
原文地址:http://www.cnblogs.com/angelxing/p/5031521.html