ca88编程iOS关于Block的大循环引用难题总括

作者:ca88编程

有个难题当大家率先次接触block的时候势必会听到block要静心防御循环援引啊!!!从此新手们就记住了看见block就来个weak。可是一向在用中来未有去关爱,他妈的有一点时候依旧得以毫无weak的。。。

比方说@property (nonatomic, weak) id<CustmViewDelegate> delegate;代理要采用弱援引,因为自定义控件是加载在视图调节器中的,视图调节器view对自定义控件是强引用,假使代理属性设置为strong,则代表delegate对视图调整器也展开了强引用,会招致循环援引。导致调整器无法被放走,最后促成内部存款和储蓄器泄漏。

正文

1、 调节器VC中代理的宣示出错
代理的扬言使用assign或weak关键字,假使你用了retain、strong强援用注脚,有希望导致该难点的出现。

2、 控制器VC中使用NSTimer出错

[NSTimer scheduledTimerWithTimeInterval:1.0 
                                 target:self 
                               selector:@selector(todo:) 
                               userInfo:nil 
                                repeats:YES];

NSTimer创造时,关键在于timer对target(self)实行了强援引,对象会开展retain操作。既然是被强援用了就相应选用__weak。_weak typeof(self) weakSelf = self,并在距离页面的时候结束反应计时器截止并把机械漏刻置为nil就足以消除难点。不然会招致对象不能够自由,内存泄漏!!!
补充:
一旦在非主线程的线程中只是创办贰个NSTimer并运转,该NS提姆er是不会实行的,除非将NSTimer参加到该线程的NSRunloop中,并运行NSRunloop才行。

3、 调节器VC中Block使用不当
Block中一贯动用成员变量(self.xxx)回变成循环引用,导致具备该实例的目的无法假释。在ARC下要:

__weak Viewcontroller *weakSelf = self;

注:Block一般用copy注解,那样会把block从栈区移到堆区。那样,在block中开展回调或反向传值到上个页面时,不会冒出对象被保释,内部存款和储蓄器败露难题。

4、 由自定义封装的控件使用不当
在调节器VC中自定义的控件View的应用中盛传了现阶段VC或self,造成循环援用,这种景况下pop重回时,当前页面也不会被假释,dealloc也不会走。唯有在离开页前边,把该控件View先置为空nil。则足以。

5、 活死人对象:内部存款和储蓄器已经被回收的目的。
野指针:指向丧尸对象的指针,向野指针发送音讯会导致崩溃。
野指针错误方式在Xcode中司空见惯表现为:Thread 1:EXC_BAD_ACCESS,因为你走访了一块已经不属于您的内存。
对象已经被放出后,应将其指针置为空指针(未有指向任何对象的指针,给空指针发送消息不会报错)。
可是在实际支出中实际上遭受EXC_BAD_ACCESS荒谬时,往往很难定位到错误点,万幸Xcode提供方便的工具給大家来恒定及解析错误。
1) 在product-scheme-edit scheme-diagnostics中将enable zombie objects勾选上,下一次再出现这样的荒唐就能够正确定位了。
2) 在Xcode-open developer tool-Instruments开采工具集,选择Zombies工具得以对已设置的使用实行活死人对象检验。

那是一个异常的粗略的Block, 相比较C语言的函数是或不是认为很相似, BOOL为这几个Block的再次来到值, ^后的isInputEven为Block的函数名, int为该block接受的参数类型, =前边的int intPut是对这些参数的陈述, 在那几个block中input用来代替传入的参数. 刚开始选取Block时, 应该都会为那一个语法发烧.不过习于旧贯之后察觉实际就是平日我们用的法子的另一种写法.

VC2

  • 调整器中的代理不是weak属性
前言

恐怕相当多开拓者在付出进度中,都会遇上这些情状:当前页面被pop出栈时,调整器未有被放出,dealloc方法不走,一再切换页面时,内存激增。检查了代码,找不到没难题,登时以为脑英里100捌十多个草泥马飞奔而过,到底怎么样鬼???
好的今天我们就器重视教育授到底哪些状态会形成这么些难题应际而生。

- viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib.// 创建cusView CusView *cusView = [[CusView alloc] initWithFrame:CGRectMake(0, 64, 50, 50)]; [self.view addSubview:cusView];// 调用playButton方法 [cusView playButton:^(UIButton *play) { NSLog(@"点击了playButton"); }];}
@implementation ViewController- viewDidLoad { [super viewDidLoad]; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 200, 200)]; btn.backgroundColor = [UIColor redColor]; [self.view addSubview:btn]; [btn addTarget:self action:@selector forControlEvents:UIControlEventTouchUpInside]; }- present{ SecViewController *vc = [[SecViewController alloc] init]; [self presentViewController:vc animated:YES completion:nil];}@end
  • 调控器中NSTimer没有被灭绝
结语:

多数就这么些了,如若各位何人还遭逢任何情状,应接补充。

viewController中button的点击方法

以此结放在心里相当久了,先天做了三个demo测量检验了一下。

当调整器中设有NSTimer时,就需求潜心,因为当[ca88编程,NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTime:) userInfo:nil repeats:YES];时,这一个/target:self/ 就充实了VC的RetarnCountr, 如若你不将以此timer invalidate,就别想调用dealloc。须要在viewWillDisappear在此以前需求把调控器用到的NSTimer销毁。[timer invalidate]; // 销毁timertimer = nil; // 置nil

那篇小说小编最主若是说一下在品种中出现的难点,重要照旧 block 内部未对质量进行弱援引,小说中关键参照了[] 那篇文章,况兼 copy 了众多并构成本身在项目中冒出的主题素材,本人才疏学浅,小说中有不当的地方还请各位同事指正,并一齐调换,十分谢谢!

#import <UIKit/UIKit.h>@interface CusView : UIView// block作为方法参数- playButton:(UIButton *play))playButton;@end
typedef void  ;@interface TestView : UIView@property (nonatomic,copy) Block block;@end
  • 调节器中block的巡回援用block会把它在那之中的有所目的强援用/PS:MRC下会retain加1/,满含方今调节器self,因而有望会并发循环援引的标题。即一个对象有一个Block属性,不过那一个Block属性中又引述了对象的别的成员变量,那么就能够对这几个变量本人发生强应用,那么那个目的自己和她和睦的Block属性就产生了巡回援引。在ARC下须求修改成那样:(/约等于生成叁个对本人对象的弱援用/)__weak typeof weakSelf = self;即:保障起见block中有着的涉嫌到self的全给替换到weakSelf
#import "CusView.h"@interface CusView ()@property (nonatomic, strong) UIButton *playButton;// 带一个参数的block属性@property (nonatomic, copy) void (UIButton * play);@end@implementation CusView- (instancetype)initWithFrame:frame { self = [super initWithFrame:frame]; if  { _playButton = [UIButton buttonWithType:UIButtonTypeCustom]; _playButton.backgroundColor = [UIColor yellowColor]; [_playButton addTarget:self action:@selector(playButtonClicked:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:_playButton]; } return self;}- layoutSubviews { [super layoutSubviews]; _playButton.frame = CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame));}// 带block参数的方法- playButton:(UIButton *))playButton { self.playBut = playButton;}- playButtonClicked:(UIButton *)playButton { self.playBut(playButton);}@end

上边大约是面试时候的标题:block在什么意况下会产出循环征引?答:举例调节器在运用一个Block,这一个block又在行使调控器就能够油但是生循环援引。。。(作者自认为答的很完美)前边那些汉子儿又加了一句:假若调整器未有通过三天性质来strong贰个Block,那么还有或然会不会冒出循环援引?。。。他既是那样问,其实哥的下意识是以为不会的,但是根本不曾核准过就从未直面回答,害怕打错了,就把话题绕开了。

前言:今天同事忽地跟自个儿说,工程里有成都百货上千调节器并未有销毁,关于这几个标题小编间接没太在意,就趁着有的时候光就查了查资料然后开展改动和测试,获得了以下结论!怎么着查看调节器是不是销毁,大家在 ARC 形式下得以重写 dealloc 方法,能够打个断点恐怕 NSLog 一下,倘若未奉行就证实当前调控器未被销毁,恐怕假若你想查看当前调节器的援引计数能够在视图就要消失的不二等秘书技中打个断点,在调整台试行po self.retainCount 就能看出眼下调节器被引述的计数了,当然在这里打字与印刷实际上是禁止的!!!调整器在被pop后移出栈后会被假释,但稍事时候会发掘调控器出栈的时候不会调用dealloc方法,归根结蒂,是因为方今调整器被某些对象强援引了,调控器的援用计数不为0,系统不能帮你释放这一部分内部存款和储蓄器。注:重写 deallocd方法不必要手动调用父类的dealloc,手写[super dealloc]方法会报错,事实上系统会自动帮您调用父类的dealloc方法,不要求你落成。能够透过在dealloc方法中打字与印刷log查看调节器是或不是被放飞。

  • Block的两种情势

View:

以下是自己工程中出现的主题材料,同仁们也得以在大团结的花色中从以下几点出发查看1.在 block 内部无论是属性大概是实例变量都会在 block 内部被强援用,所以在检讨时要注意内部的性质可能实例变量是不是开展了弱引用,作者当下的化解办法是将实例变量改为了属性!2.在系统一编写译时,即便大家未试行block 的内部代码,不过编写翻译器在编译时都会暗中认可读取的,所以在项目中您感觉相当多未实行或写在 return 前面你认为不会实践的代码系统都会编译的,尽量做到永不的代码删除掉!3.要是项目中大家使用了自定义的视图,假若在自定义的视图中援引了有些调节器,我们要将调控器实行一遍弱援用,制止出现循环引用的主题素材!

ViewController.m

VC1

BOOL (^isInputEven) = ^(int input) { if (input % 2 == 0) { return YES; } else { return NO; } };

本文由ca88发布,转载请注明来源

关键词: iOS开发( 小结 iOS Block 未被