前言:
最近遇到了一个block的循环引用的问题,才发现我对block还一知半解,为此,对自己的理解做了一下正整理。
目录:
1、什么是block ?有什么作用?
2、block为什么使用copy修饰?
3、block为什么会造成循环引用?怎么解决?
4、block中基本数据类型,数值无法更改。
1、什么是block?有什么作用?
代码块Block是苹果在iOS4开始引入的对C语言的扩展,用来实现匿名函数的特性,Block是一种特殊的数据类型,其可以正常定义变量、作为参数、作为返回值,特殊地,Block还可以保存一段代码,在需要的时候调用,目前Block已经广泛应用于iOS开发中,常用于GCD、动画、排序及各类回调。存储的数据是一个函数体。使用Block,就可以像其他标准函数一样,传入参数,并得到返回值。
block的格式:
a:Block的返回值类型,可以为空(void);
b:Block对象名称,可以理解为变量名;
^:块的语法标记,声明b为一个Block对象;
c:第一个参数类型
d:第二个参数类型
name1,name2:参数名;
{}:Block代码块的主题部分。
block的声明:
例子:控制器A,控制器B,在A中点击button push到B,pop时从B传值到A。block为B中的属性和方法。
方式一:
typedef void(^testBlock)(void); // 定义类型,取别名
@property (nonatomic, copy) testBlock Block; // 再声明属性
实现:
B中:
_testBlock(@"1");
A中:
b.testBlock = ^(NSString *text) {
nslog(@"%@",text);
};
方式二:
@property (nonatomic, copy) void(^test1Block)(NSString *text); // 直接声明属性
实现:
B中:
_test1Block(@"1");
A中:
b.test1Block = ^(NSString *text) {
nslog(@"%@",text);
};
方式三:
-(void)testWithBlock:(void(^)(NSString *text))block; // 作为函数参数
实现:
B中:
- (void)testWithBlock:(void (^)(NSString *))block{
block(@"1");
}
A中:
[a testWithBlock:^(NSString *text) {
nslog(@"%@",text);
}];
2、block为什么使用copy修饰?
a、block在创建的时候默认分配的内存是在栈上,而不是在堆上。这样的话其本身的作用域是属于创建时候的作用域,一旦在创建的作用域之外调用就会导致程序的崩溃。所以使用了copy将其拷贝到堆内存上。
b、block创建在栈上,而block的代码中可能会用到本地的一些变量,只有将其拷贝到堆上,才能用这些变量
3、block为什么会造成循环引用?怎么解决?
self 与 block 相互持有,形成保留环,无法释放,导致循环引用内存泄露
例子一:
self.b.test1Block = ^(NSString *text) {
nslog(@"%@",text);
[self.test1_btn setTitle:text forState:UIControlStateNormal];
};
情况:未执行dealloc 内存泄露 self->b->block->self
解决办法:打破retain cycle
__weak typeof(self) weakSelf = self;
[weakSelf.test1_btn setTitle:text forState:UIControlStateNormal];
例子二:
LHQTest2ViewController *b = [[LHQTest2ViewController alloc]init];
[self.navigationController pushViewController:b animated:YES];
b.test2Block = ^(NSString *text) {
[self.test1_btn setTitle:text forState:UIControlStateNormal];
};
情况:执行dealloc 不泄露 b->block->self
例子三:
b = [[LHQTest2ViewController alloc]init]; //test2为局部变量
[self.navigationController pushViewController:test2 animated:YES];
b.test2Block = ^(NSString *text) {
[self.test2_btn setTitle:text forState:UIControlStateNormal];
};
情况:未执行dealloc 内存泄露 self->b->block->self
解决办法:与例子一一样
例子四:
self.b.test2Block = ^(NSString *text) {
_msg = text; // _msg未局部变量
};
情况:未执行dealloc 内存泄露 self->b->block->self
解决办法:打破retain cycle
__weak typeof(self) weakSelf = self;
self.b.test2Block = ^(NSString *text) {
__strong typeof(weakSelf) strongSelf = weakSelf;
// strongSelf和原来的self并没有直接关系,因为strongSelf是通过weakSelf得来的,而weakSelf又没有强引用原来的sel
strongSelf->_msg = text;
};
4、block中基本数据类型,数值无法更改。
对于基本数据类型,进入到block中会被当做常量处理
//如果需要在block中对num进行修改,需要加上关键字__block
//(我们也可以用static关键字进行修饰)
__block int num = 10; // 使进入到block块中的变量不被当做常量来使用
b.test2Block = ^(NSString *text) {
num += 1;
NSLog(@"num is %d",num);
};
网友评论