Block中的循环引用,iOS中block的巡回引用难题

By admin in 4858.com on 2019年5月2日

不会促成循环引用的block

在讲block的大循环引用难点之前,大家须求先精通一下iOS的内部存款和储蓄器管理机制和block的基本知识

本文首要介绍ARC下block的巡回引用难点,举例表达引起循环引用的气象和对应的缓和方案。

总的说来那壹切实际正是为着幸免循环引用,上面结合互连网上各位大咖的辨析卓绝分析分析

大部分GCD方法

1 dispatch_async(dispatch_get_main_queue(), ^{
2     [self doSomething];
3 });

因为self并不曾对GCD的block进行富有,未有产生巡回引用。近东瀛身还没遇上使用GCD导致循环引用的风貌,若是某种场景self对GCD的block实行了装有,则才有极大可能率形成循环引用。

 

iOS的内部存款和储蓄器处理机制

在讲block的循环引用难点在此以前,大家要求先领会一下iOS的内部存储器管理机制和block的基本知识

block对于其变量都会造成强引用(retain),对于self也会产生强引用(retain)
,而假设self自个儿对block也是强引用的话,就能产生 强引用
循环,无法自由——产生内部存款和储蓄器走漏
如何是循环引用:对象A持有对象B,对象B持有对象A,互相持有,最后导致四个对象都不能够释放。

block并不是属性值,而是暂且变量

 1 - (void)doSomething {
 2     [self testWithBlock:^{
 3         [self test];
 4     }];
 5 }
 6 
 7 - (void)testWithBlock:(void(^)())block {
 8     block();
 9 }
10 
11 - (void)test {
12     NSLog(@"test");
13 }

此间因为block只是1个一时变量,self并未对其具有,所以并未有导致循环引用

 

Objective-C在iOS中不协助GC(垃圾回收)机制,而是使用的引用计数的秘籍处理内部存款和储蓄器。

iOS的内部存款和储蓄器管理机制

Objective-C在iOS中不帮衬GC机制,而是利用的引用计数的方法管理内部存款和储蓄器。

在引用计数中,每3个目标承担掩护对象具有引用的计数值。当叁个新的引用指向对象时,引用计数器就星罗棋布,当去掉多个引用时,引用计数就递减。当引用计数到零时,该目的就将释放占领的财富。

笔者们由此开关房间的灯为例来�说明引用计数机制。

4858.com 1引用《Pro
Multithreading and Memory Management for iOS and OS X》中的图片

图中,“必要照明的人数”即对应大家要说的引用计数值。

  1. 率先民用进来办公,“须要照明的总人口”加一,计数值从0变为壹,由此必要开灯;
  2. 尔后每当有人进入办公,“需求照明的总人口”就加一。如计数值从一变成二;
  3. 每当有人下班离开办公,“供给照明的食指”加减1如计数值从2产生1;
  4. 末段一个人下班离开办公室时,“须求照明的食指”减一。计数值从一形成0,由此要求关灯。

在Objective-C中,”对象“相当于办公的照明设备,”对象的利用蒙受“相当于进入办公的人。上班进入办公室的人对办公室照明设备发出的动作,与Objective-C中的对应关系如下表

对照明设备所做的动作 对Objective-C对象所做的动作
开灯 生成对象
需要照明 持有对象
不需要照明 释放对象
关灯 废弃对象

应用计数成效计算供给照明的人口,使办公室的照明得到了很好的管制。一样,使用引用计数效率,对象也就能够赢得很好的管住,那正是Objective-C内部存款和储蓄器管理,如下图所示

4858.com 2引用《Pro
Multithreading and Memory Management for iOS and OS X》中的图片

Objective-C对象方法 说明
alloc/new/copy/mutableCopy 创建对象,引用计数加1
retain 引用计数加1
release 引用计数减1
dealloc 当引用计数为0时调用
[NSArray array] 引用计数不增加,由自动释放池管理
[NSDictionary dictionary] 引用计数不增加,由自动释放池管理

至于机关释放,不是本文的关键,这里就不讲了。

Objective-C对象所有权修饰符 说明
__strong 对象默认修饰符,对象强引用,在对象超出作用域时失效。其实就相当于retain操作,超出作用域时执行release操作
__weak 弱引用,不持有对象,对象释放时会将对象置nil。
__unsafe_unretained 弱引用,不持有对象,对象释放时不会将对象置nil。
__autoreleasing 自动释放,由自动释放池管理对象

巡回引用场景:
壹、block在主函数体用到了self / self.变量 / [self
方法],意味着:block对self 实行具有操作;
2、self表明了质量变量block,block用copy来修饰,意味着:self对block进行具备操作,会形成循环引用;
举个例子下图,以往如此写Xcode直接就能够有警示出来告诉您这边貌似retain
cycle了哟!!

block使用对象被提前出狱

有那种意况,即便不只是ClassA持有了myBlock,ClassB也兼具了myBlock。

4858.com 3

当ClassA被someObj对象释放后

4858.com 4

那时候,ClassA对象已经被保释,而myBlock还是被ClassB持有,未有自由;假使myBlock那几个时被调治,而那时候ClassA已经被放走,此时做客的ClassA将是八个nil对象(使用__weak修饰,对象释放时会置为nil),而吸引错误。

 

另二个大面积错误采用是,开荒者思念循环引用错误(如上所述不会出现循环引用的意况),使用__weak。比如

1 __weak typeof(self) weakSelf = self;
2 dispatch_async(dispatch_get_main_queue(), ^{
3     [weakSelf doSomething];
4 });

因为将block作为参数字传送给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的目的,因为dispatch_async并不知道block中目标会在如什么时候候被放飞,为了保险系统调整施行block中的任务时其目标未有被意外释放掉,dispatch_async必须团结retain贰次对象(即self),任务到位后再release对象(即self)。但这里运用__weak,使dispatch_async未有扩充self的引用计数,这使得在系统在调治试行block此前,self恐怕已被灭绝,但系统并不知道这几个情形,导致block推行时访问已经被假释的self,而达不到预期的结果。

 

Block中的循环引用,iOS中block的巡回引用难题。引用计数(Reference Count)

block的基本知识

block的基本知识这里就不细说了,能够看看本身的小说说说Objective-C中的block

4858.com 5

注:要是是在M福睿斯C方式下,使用__block修饰self,则此时block访问被放出的self,则会促成crash。 

这一场景下的代码

 1 // ClassA.m
 2 - (void)test {
 3     __weak MyClass* weakSelf = self;
 4     double delayInSeconds = 10.0f;
 5     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
 6     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
 7         NSLog(@"%@", weakSelf);
 8     });
 9 }
10 
11 // ClassB.m
12 - (void)doSomething {
13     NSLog(@"do something");
14     ClassA *objA = [[ClassA alloc] init];
15     [objA test];
16 }

运转结果

[5988:435396] do something
[5988:435396] self:(null)

缓慢解决方式:

对于那种光景,就不应有利用__weak来修饰对象,让dispatch_after对self举办富有,保险block执行时self还未被放走。

 

在引用计数中,每2个目标承担爱抚对象具备引用的计数值。当一个新的引用指向对象时,引用计数器就俯10皆是,当去掉3个引用时,引用计数就递减。当引用计数到零时,该对象就将释放据有的财富。

巡回引用难题

四个对象互相持有,那样就能够导致循环引用,如下图所示

4858.com 6八个目的相互持有

图中,对象A持有对象B,对象B持有对象A,互相持有,最后变成多个目的都无法释放。

是因为block会对block中的对象进行具备操作,就也便是具备了中间的目的,而1旦那时候block中的对象又独具了该block,则会促成循环引用。如下,

typedef void;@property (copy, nonatomic) block myBlock;@property (copy, nonatomic) NSString *blockString;- testBlock { self.myBlock = ^() { //其实注释中的代码,同样会造成循环引用 NSString *localString = self.blockString; //NSString *localString = _blockString; //[self doSomething]; };}

注:以下调用注释掉的代码同样会促成循环引用,因为无论是因而self.blockString还是_blockString,或是函数调用[self doSomething],因为只要
block中用到了对象的性质也许函数,block就能够怀有该目的而不是该目的中的有个别属性或许函数。

当有someObj持有self对象,此时的关联图如下。

4858.com 7

当someObj对象release
self对象时,self和myblock互相引用,retainCount都为一,变成循环引用

4858.com 8

减轻格局:

__weak typeof weakSelf = self;self.myBlock = ^() { NSString *localString = weakSelf.blockString;};

使用__weak修饰self,使其在block中不被抱有,打破循环引用。初始境况如下

4858.com 9

当someObj对象释放self对象时,Self的retainCount为0,走dealloc,释放myBlock对象,使其retainCount也为0。

4858.com 10

实际以上循环引用的情状很轻巧觉察,因为那时Xcode就能够报告警察方告。而发生在多少个目标间的时候,Xcode就检查评定不出去了,那频仍就轻便被忽视。

//ClassB@interface ClassB : NSObject@property (strong, nonatomic) ClassA *objA;- doSomething;@end //ClassA@property (strong, nonatomic) ClassB *objB;@property (copy, nonatomic) block myBlock;- testBlockRetainCycle { ClassB* objB = [[ClassB alloc] init]; self.myBlock = ^() { [objB doSomething]; }; objB.objA = self;}

4858.com 11

化解办法:

- testBlockRetainCycle { ClassB* objB = [[ClassB alloc] init]; __weak typeof weakObjB = objB; self.myBlock = ^() { [weakObjB doSomething]; }; objB.objA = self;}

将objA对象weak,使其不在block中被有着

注:以上使用__weak打破循环的秘诀只在A本田CR-VC下才使得,在MGL450C下应该使用__block

要么,在block试行完后,将block置nil,那样也得以打破循环引用

- testBlockRetainCycle { ClassB* objB = [[ClassB alloc] init]; self.myBlock = ^() { [objB doSomething]; }; objA.objA = self; self.myBlock(); self.myBlock = nil;}

这么做的欠缺是,block只会施行一遍,因为block被置nil了,要再度行使以来,须要再一次赋值。

在支付工程中,开采部分同班并不曾完全明了循环引用,认为只要有block的地点就能够要用__weak来修饰对象,那样没有要求,以下二种block是不会促成循环引用的。

dispatch_async(dispatch_get_main_queue(), ^{ [self doSomething];});

因为self并从未对GCD的block进行富有,未有变异巡回引用。近来自个儿还没境遇使用GCD导致循环引用的现象,假诺某种场景self对GCD的block实行了具备,则才有十分大可能率导致循环引用。

- doSomething { [self testWithBlock:^{ [self test]; }];}- testWithBlock:)block { block();}- test { NSLog;}

那边因为block只是四个一时变量,self并不曾对其具有,所以未有导致循环引用

看上面例子,有这种状态,要是不只是ClassA持有了myBlock,ClassB也存有了myBlock。

4858.com 12

当ClassA被someObj对象释放后

4858.com 13

那时,ClassA对象已经被假释,而myBlock依旧被ClassB持有,未有自由;借使myBlock这几个时被调整,而那时候ClassA已经被放出,此时走访的ClassA将是四个nil对象(使用__weak修饰,对象释放时会置为nil),而吸引错误。

另三个大规模错误选取是,开采者挂念循环引用错误(如上所述不汇合世循环引用的景色),使用__weak。比如

__weak typeof weakSelf = self;dispatch_async(dispatch_get_main_queue(), ^{ [weakSelf doSomething];});

因为将block作为参数字传送给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的对象,因为dispatch_async并不知道block中目标会在怎么时候被放走,为了确定保证系统调节施行block中的职务时其目的未有被意外释放掉,dispatch_async必须和谐retain二回对象,职责达成后再release对象。但此间运用__weak,使dispatch_async未有扩充self的引用计数,那使得在系统在调节执行block以前,self或者已被灭绝,但系统并不知道那么些场馆,导致block试行时访问已经被放飞的self,而达不到预期的结果。

注:要是是在MKoleosC方式下,使用__block修饰self,则此时block访问被释放的self,则会招致crash。

该现象下的代码

// ClassA.m- test { __weak MyClass* weakSelf = self; double delayInSeconds = 10.0f; dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (delayInSeconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), ^{ NSLog(@"%@", weakSelf); });}// ClassB.m- doSomething { NSLog(@"do something"); ClassA *objA = [[ClassA alloc] init]; [objA test];}

运作结果

[5988:435396] do something[5988:435396] self:

消除措施:

对于这种现象,就不应当利用__weak来修饰对象,让dispatch_after对self进行富有,保障block施行时self还未被保释。

再有1种情景,在block施行起来时self对象还未被释放,而推行进程中,self被假释了,此时拜会self时,就能够产生错误。

对于那种气象,应该在block中对 对象使用__strong修饰,使得在block时期对
对象具备,block实践完结后,解除其有着。

- testBlockRetainCycle { ClassA* objA = [[ClassA alloc] init]; __weak typeof weakObjA = objA; self.myBlock = ^() { __strong typeof strongWeakObjA = weakObjA; [strongWeakObjA doSomething]; }; objA.objA = self;}

注:此措施只好确认保证在block施行时期对象不被假释,要是目标在block推行施行在此以前早已被保释了,该办法也行不通。

巡回引用例子

block推行进度中目的被假释

还有1种情景,在block实施起来时self对象还未被释放,而推行进程中,self被假释了,此时拜会self时,就能生出错误。

对于那种情景,应该在block中对 对象使用__strong修饰,使得在block时期对
对象具有,block推行完结后,解除其抱有。

1 - (void)testBlockRetainCycle {
2     ClassA* objA = [[ClassA alloc] init];
3     __weak typeof(objA) weakObjA = objA;
4     self.myBlock = ^() {
5         __strong typeof(weakObjA) strongWeakObjA = weakObjA;
6         [strongWeakObjA doSomething];
7     };
8     objA.objA = self;
9 }

 

注:此措施只可以确认保证在block实行时期对象不被假释,若是目的在block实践实施从前早已被放出了,该办法也不行。

 

参考资料:block的轮回引用难题

咱俩由此开关房间的灯为例来�表达引用计数机制。

假诺本身想在block里面退换部分变量的值可能选择一些变量,如下图那样写Xcode直接报错
而且付出了消除措施提醒出来了
那一点还挺机智的,那么大家选用__block修饰之后,再一次在block里面使用,就不会出难题了,完美。

4858.com 14

4858.com 15

引用《Pro Multithreading and Memory Management for iOS and OS
X》中的图片

解决

图中,“要求照明的人头”即对应我们要说的引用计数值。

首先私人住房进来办公室,“须要照明的人头”加1,计数值从0变为壹,由此须要开灯;

4858.com 16

自此每当有人进来办公,“须要照明的人数”就加一。如计数值从一产生2;

应用一些变量.png

每当有人下班离开办公,“供给照明的人头”加减1如计数值从贰形成一;

在使用block的地方:
__block typeof(self) bself = self;          // 适用MRC模式,
__block NSString *tempStr = @"abc";
__block int a = 0; //当修饰变量时,表示这个变量值能在block中被修改
__weak typeof(self) weakself = self;     // 适用ARC模式

倒数一位下班离开办公时,“供给照明的人头”减一。计数值从1形成0,因而须要关灯。

至于——Block在MCRUISERC和A猎豹CS6C形式的分歧
1)__block在M帕JeroC下有五个效益
同意在Block中走访和更改部分变量
禁绝Block对所引用的目的开始展览隐式retain操作

在Objective-C中,”对象“也正是办公的照明设备,”对象的应用条件“相当于进入办公的人。上班进入办公的人对办公室照明设备发出的动作,与Objective-C中的对应关系如下表

2)__block在A哈弗C下唯有多少个作用
同目的在于Block中做客和退换部分变量

对照明设备所做的动作对Objective-C对象所做的动作

什么样时候在 block 中无需采用 weakSelf???

开灯生成对象

  • 大大多GCD方法,因为self并未对GCD的block进行具有,未有变异巡回引用。近年来自家还没蒙受使用GCD导致循环引用的气象,借使某种场景self对GCD的block实行了富有,则才有望引致循环引用。

内需照明持有对象

dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});

没有供给照明释放对象

  • 许多动画片效果,当动画甘休时,UIView 会截至全体那几个 block,block
    对象就能自由掉,从而 block 会释放掉对于 self
    的有所。整个内部存款和储蓄器引用关系被免除。

关灯扬弃对象

[UIView animateWithDuration:0.2 animations:^{
self.alpha = 1;
}];

选取计数功效总计需求照明的总人口,使办公室的照明获得了很好的军管。同样,使用引用计数作用,对象也就会获取很好的管理,那正是Objective-C内部存款和储蓄器管理,如下图所示

  • block并不是目的的性格 / 变量,而是方法的参数 /
    权且变量,这里因为block只是3个一时半刻变量,self并不曾对其独具,所以未有导致循环引用

4858.com 17

.- (void) testWithBlock:(void(^)())block {
block();
}

引用《Pro Multithreading and Memory Management for iOS and OS
X》中的图片

  • 再有一种景况,block属于Person对象,在另多少个类里面使用的时候从不构成互争持有,这时候也没有须求weakSelf。

  • 利用GCD的时候,这么写实际是不对的,并不是观望block将在为了防御循环引用而使用weakSelf,像上面那种写法,正是荒谬的:

MEnclaveC(马努al Reference Counting)中滋生应用计数变化的点子

__weak typeof(self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf doSomething];
});

Objective-C对象方法求证

因为将block作为参数传给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的对象,因为dispatch_async并不知道block中目的会在哪天被假释,为了确认保障系统调节实施block中的职分时其目的未有被意外释放掉,dispatch_async必须和睦retain2回对象(即self),职分成功后再release对象(即self)。但此间运用__weak,使dispatch_async未有增添self的引用计数,那使得在系统在调整推行block从前,self或者已被灭绝,但系统并不知道这些情状,导致block实施时访问已经被放出的self,而达不到预期的结果。

alloc/new/copy/mutableCopy创立对象,引用计数加一

总结
一 在 Block 内如若须要拜访 self 的办法、变量,提出利用 weakSelf。
贰 假如在 Block 内必要频仍 访问 self,则供给采取 strongSelf。

retain引用计数加1

release引用计数减1

dealloc当引用计数为0时调用

[NSArray array]引用计数不扩大,由活动释放池管理

[NSDictionary dictionary]引用计数不扩大,由机关释放池管理

机关释放池

至于机关释放,不是本文的机要,这里就不讲了。

ACRUISERC(Automatic Reference Counting)中内部存储器管理

Objective-C对象全数权修饰符表达

__strong对象私下认可修饰符,对象强引用,在对象超越成效域时失效。其实就一定于retain操作,超过成效域时实施release操作

__weak弱引用,不持有对象,对象释放时会将目的置nil。

__unsafe_unretained弱引用,不持有对象,对象释放时不会将对象置nil。

__autoreleasing自动释放,由自动释放池管理对象

block的基本知识

block的基本知识这里就不细说了。

循环引用难题

三个对象互相持有,那样就能够形成循环引用,如下图所示

4858.com 18

四个目的相互持有

图中,对象A持有对象B,对象B持有对象A,互相持有,最终促成八个对象都不能自由。

block中循环引用难题

由于block会对block中的对象进行具备操作,就一定于具备了中间的靶子,而尽管此时block中的对象又颇具了该block,则会产生循环引用。如下,

typedef void(^block)();

@property (copy, nonatomic) block myBlock;

@property (copy, nonatomic) NSString *blockString;

– (void)testBlock {

self.myBlock = ^() {

//其实注释中的代码,同样会促成循环引用

NSString *localString = self.blockString;

//NSString *localString = _blockString;

//[self doSomething];

};

}

4858.com,注:以下调用注释掉的代码同样会促成循环引用,因为不管是由此self.blockString依旧_blockString,或是函数调用[self
doSomething],因为假如block中用到了对象的习性恐怕函数,block就能够怀有该目的而不是该目的中的有些属性只怕函数。

当有someObj持有self对象,此时的关联图如下。

4858.com 19

当someObj对象release
self对象时,self和myblock互相引用,retainCount都为一,形成循环引用

4858.com 20

减轻方式:

__weak typeof(self) weakSelf = self;

self.myBlock = ^() {

NSString *localString = weakSelf.blockString;

};

使用__weak修饰self,使其在block中不被有着,打破循环引用。开端处境如下

4858.com 21

当someObj对象释放self对象时,Self的retainCount为0,走dealloc,释放myBlock对象,使其retainCount也为0。

4858.com 22

实际以上循环引用的气象很轻易觉察,因为此时Xcode就能报警告。而发出在四个目的间的时候,Xcode就检查测试不出去了,那频仍就轻巧被忽视。

//ClassB

@interface ClassB : NSObject

@property (strong, nonatomic) ClassA *objA;

– (void)doSomething;

@end

//ClassA

@property (strong, nonatomic) ClassB *objB;

@property (copy, nonatomic) block myBlock;

– (void)testBlockRetainCycle {

ClassB* objB = [[ClassB alloc] init];

self.myBlock = ^() {

[objB doSomething];

};

objB.objA = self;

}

4858.com 23

消除办法:

– (void)testBlockRetainCycle {

ClassB* objB = [[ClassB alloc] init];

__weak typeof(objB) weakObjB = objB;

self.myBlock = ^() {

[weakObjB doSomething];

};

objB.objA = self;

}

将objA对象weak,使其不在block中被全部

注:以上使用__weak打破循环的主意只在A瑞虎C下才使得,在M路虎极光C下相应利用__block

要么,在block实施完后,将block置nil,那样也能够打破循环引用

– (void)testBlockRetainCycle {

ClassB* objB = [[ClassB alloc] init];

self.myBlock = ^() {

[objB doSomething];

};

objA.objA = self;

self.myBlock();

self.myBlock = nil;

}

如此那般做的欠缺是,block只会进行三次,因为block被置nil了,要重新行使以来,须求再行赋值。

有个别不会导致循环引用的block

在开拓工程中,开掘一些同室并未有完全驾驭循环引用,感到壹旦有block的地点就能要用__weak来修饰对象,那样大可不必,以下二种block是不会招致循环引用的。

大部分GCD方法

dispatch_async(dispatch_get_main_queue(), ^{

[self doSomething];

});

因为self并不曾对GCD的block进行具有,未有形成巡回引用。近日作者还没遇上使用GCD导致循环引用的风貌,假若某种场景self对GCD的block实行了装有,则才有非常大或然形成循环引用。

block并不是属性值,而是一时半刻变量

– (void)doSomething {

[self testWithBlock:^{

[self test];

}];

}

– (void)testWithBlock:(void(^)())block {

block();

}

– (void)test {

NSLog(@”test”);

}

此地因为block只是1个目前变量,self并未对其颇具,所以并未变成循环引用

block使用对象被提前释放

看上面例子,有这种状态,倘若不只是ClassA持有了myBlock,ClassB也保有了myBlock。

4858.com 24

当ClassA被someObj对象释放后

4858.com 25

那儿,ClassA对象已经被放飞,而myBlock依然被ClassB持有,未有自由;假使myBlock这么些时被调解,而那时ClassA已经被假释,此时拜会的ClassA将是八个nil对象(使用__weak修饰,对象释放时会置为nil),而引发错误。

另一个宽广错误使用是,开垦者顾忌循环引用错误(如上所述不会现出循环引用的意况),使用__weak。比如

__weak typeof(self) weakSelf = self;

dispatch_async(dispatch_get_main_queue(), ^{

[weakSelf doSomething];

});

因为将block作为参数字传送给dispatch_async时,系统会将block拷贝到堆上,而且block会持有block中用到的目的,因为dispatch_async并不知道block中目的会在哪些时候被保释,为了确认保证系统调解推行block中的职分时其目的未有被意外释放掉,dispatch_async必须团结retain一次对象(即self),职务成功后再release对象(即self)。但此间运用__weak,使dispatch_async未有扩充self的引用计数,那使得在系统在调治试行block在此之前,self可能已被灭绝,但系统并不知道这几个状态,导致block施行时访问已经被放走的self,而达不到预期的结果。

注:如若是在M锐界C格局下,使用__block修饰self,则此时block访问被放走的self,则会招致crash。

该现象下的代码

// ClassA.m

– (void)test {

__weak MyClass* weakSelf = self;

double delayInSeconds = 10.0f;

dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(delayInSeconds * NSEC_PER_SEC));

dispatch_after(popTime, dispatch_get_main_queue(), ^(void){

NSLog(@”%@”, weakSelf);

});

}

// ClassB.m

– (void)doSomething {

NSLog(@”do something”);

ClassA *objA = [[ClassA alloc] init];

[objA test];

}

运作结果

[5988:435396] do something

[5988:435396] self:(null)

化解措施:

对此那种光景,就不该使用__weak来修饰对象,让dispatch_after对self实行具备,保险block执行时self还未被放飞。

block试行进度中目标被假释

还有1种情景,在block实践起来时self对象还未被释放,而施行进度中,self被释放了,此时拜会self时,就能够发生错误。

对于那种景观,应该在block中对 对象使用__strong修饰,使得在block时期对
对象具有,block实践实现后,解除其具有。

– (void)testBlockRetainCycle {

ClassA* objA = [[ClassA alloc] init];

__weak typeof(objA) weakObjA = objA;

self.myBlock = ^() {

__strong typeof(weakObjA) strongWeakObjA = weakObjA;

[strongWeakObjA doSomething];

};

objA.objA = self;

}

注:此方法只好保障在block实施时期对象不被假释,假使目标在block实施实践以前早已被保释了,该形式也没用。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有