Fork me on GitHub

Block学习

写在前面

首先对大家的Block进行下测试,这边有5道题

介绍

Block是Objective-C对于闭包的实现,有关闭包,我正在想一个通俗的方式给大家定义下。

闭包:函数中的函数。

Block的基本理解

Block的两种使用方式:

  1. Block变量,这种就是相当于内联函数,很简单。
  2. Block函数,这个就是Block强大的地方,block外的变量可以无缝地直接在block内部使用。

Block在使用时是可以调用外部变量的,Block将使用到的、作用域附近到的变量的值建立一份快照拷贝到栈上。而在ARC下就可能会出现循环引用的情况,我们等下来讲。

Block的内存管理

在 Objective-C 语言中,一共有 3 种类型的 block:

  1. NSConcreteGlobalBlock 全局的静态 block,不会访问任何外部变量。

  2. NSConcreteStackBlock 保存在栈中的 block,当函数返回时会被销毁。

  3. NSConcreteMallocBlock 保存在堆中的 block,当引用计数为 0 时会被销毁。

在ARC下,不使用第二种内存管理方式,所有的外部变量使用时都是第三种方式。

循环引用的问题

循环引用 (retain cycle)问题的根源在于ARC中Block和obj可能会互相强引用,互相retain对方,这样就导致了retain cycle,无法释放,造成内存泄露。

首先看下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
@interface MyClass : NSObject {
NSObject* _instanceObj;
}
@end
@implementation MyClass
NSObject* __globalObj = nil;
- (id) init {
if (self = [super init]) {
_instanceObj = [[NSObject alloc] init];
}
return self;
}
- (void) test {
static NSObject* __staticObj = nil;
__globalObj = [[NSObject alloc] init];
__staticObj = [[NSObject alloc] init];
NSObject* localObj = [[NSObject alloc] init];
__block NSObject* blockObj = [[NSObject alloc] init];
typedef void (^MyBlock)(void) ;
MyBlock aBlock = ^{
NSLog(@"%@", __globalObj);
NSLog(@"%@", __staticObj);
NSLog(@"%@", _instanceObj);
NSLog(@"%@", localObj);
NSLog(@"%@", blockObj);
};
aBlock = [[aBlock copy] autorelease];
aBlock();
NSLog(@"%d", [__globalObj retainCount]);
NSLog(@"%d", [__staticObj retainCount]);
NSLog(@"%d", [_instanceObj retainCount]);
NSLog(@"%d", [localObj retainCount]);
NSLog(@"%d", [blockObj retainCount]);
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
MyClass* obj = [[[MyClass alloc] init] autorelease];
[obj test];
return 0;
}
}

执行结果为 1 1 1 2 1

localObj在Block copy时,系统自动retain对象,增加其引用计数。

  • 非ObjC对象,如GCD队列dispatch_queue_t。Block copy时并不会自动增加他的引用计数 *

解决办法使用弱引用 _weak

1
2
3
4
5
6
7
ClassA* objA = [[[ClassA alloc] init] autorelease];
MyClass* weakSelf = self;
objA.myBlock = ^{
[weakSelf doSomething];
};
self.objA = objA;

参考

谈Objective-C Block的实现
正确使用Block避免Cycle Retain和Crash


版权声明



Ivan’s Blog by Ivan Ye is licensed under a Creative Commons BY-NC-ND 4.0 International License.
叶帆创作并维护的叶帆的博客博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证

本文首发于Ivan’s Blog | 叶帆的博客博客( http://yeziahehe.com ),版权所有,侵权必究。

本文链接:http://yeziahehe.com/2015/10/10/Block_learning/