您的位置:首页 > 其它

关于block和引用计数

2016-03-07 11:12 295 查看
(1)修饰block

如果需要block在它被声明的作用域被销毁后继续使用的话,你就需要做一份拷贝。拷贝会把block移到堆里面。所以,使用@property时设置通常如下:

@property(copy, nonatomic)void(^block)(void);

(2)retain cycle的问题

block在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在block块内使用该只读拷贝。所以在使用block过程中,经常会遇到retain cycle的问题,例如:

1 - (void)dealloc

2 {

3 [[NSNotificationCenter defaultCenter] removeObserver:_observer];

4 }

5 - (void)loadView

6 {

7 [super loadView];

8

9 _observer = [[NSNotificationCenterdefaultCenter] addObserverForName:@”testKey”

10 object:nil

11 queue:nil

12 usingBlock:^(NSNotification*note)

13 {

14 [sselfdismissModalViewControllerAnimated:YES];

15 }];

16 }

在block中用到了self,self会被block retain,而_observer会copy一份该block,就是说_observer间接持有self,同时当前的self也会retain_observer,最终导致self持有_observer,_observer持有self,形成retaincycle。

对于在block中的retain cycle,在2011 WWDC Session #322 (Objective-C Advancements in Depth)有一个解决方案weak-strong dance,其实现如下:

1 - (void)dealloc

2 {

3 [[NSNotificationCenter defaultCenter] removeObserver:_observer];

4 }

5 - (void)loadView

6 {

7 [super loadView];

8

9 __weakTestViewController *wself =self;

10 _observer =[[NSNotificationCenter defaultCenter] addObserverForName:@”testKey”

11 object:nil

12 queue:nil

13 usingBlock:^(NSNotification *note)

14 {

15 TestViewController *sself = wself;

16 [sselfdismissModalViewControllerAnimated:YES];

17 }];

18 }

在block中使用self之前先用一个__weak变量引用self,导致block不会retain self,打破retain cycle,然后在block中使用wself之前先用__strong类型变量引用wself,以确保使用过程中不会dealloc。简而言之就是推迟对self的retain,在使用时才进行retain。

(3)return一个block

返回一个block时,ARC会自动将block加上autorelease,所以需要注意,如果执行过程中不能接受在runloop接受后才释放block,就需要自己加入@autoreleasepool块,但是测试发现64位iOS/mac时,系统会自动在使用结束后立即释放,32位则要等到runloop结束。

1 - (void)test

2 {

3 //@autoreleasepool{

4 AutoTest *a = [AutoTestsAutoTest];

5 NSLog(@“1”);

6 a = nil;

7 NSLog(@”2”);

8 a = [[AutoTest alloc] init];

9 //}

10 NSLog(@”3”);

11 }

12 - (IBAction)ok:(id)sender

13 {

14 [self test];

15 NSLog(@”4”);

16 }

//执行结果

1释放23释放4 64位

123释放4释放 32位

12释放释放34 32位+@autoreleasepool

(4)block作为参数

block作为参数时,如果使用范围超过了block的作用域(比如异步时,或者将block传递给其他对象等等),则需要copy此block,copy建议在使用此block的方法内实现(谁使用,谁管理),而不是在传递参数时copy。注意,block过一个strong类型的指针时,会自动copy。经过copy过的block会从栈空间移动到堆上,并且,copy一个已经在堆上的block时,此block不会受影响。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: