当前位置: 首页 > 科技观察

iOS-NSTimerCircularReference的解决方法

时间:2023-03-15 23:51:53 科技观察

出现场景ControllerB中有一个NSTimer@property(strong,nonatomic)NSTimer*timer;您创建它并将其安装到主runloopself.timer=[NSTimerscheduledTimerWithTimeInterval:1target:selfselector:@selector(timerAction:)userInfo:nilrepeats:true];那么在退出ControllerB的时候,如果忘记关闭定时器,ControllerB不会被释放,循环引用B和定时器。因为timer创建的时候直接把self写进去了。方法一由于不能直接传self,尝试传weakSelf__weaktypeof(self)weakSelf=self;self.timer=[NSTimerscheduledTimerWithTimeInterval:1target:weakSelfselector:@selector(timerAction:)userInfo:nilrepeats:true];测试结果还是出现循环引用,B没有释放,timer对变量weakSelf有强引用,timer->weakSelf->B->timer,三者之间形成循环引用。第二种方法是设置一个包装类,将ControllerB包装起来,放入定时器中。像这样,我觉得controllerB有好几MB那么大,而且会泄露浪费内存。WeakWrap也就几百个字节那么小,漏了也没关系。WeakWrap中有一个对ControllerB的弱引用。WeakWrap包装ControllerB并将其传递给计时器。即使您忘记关闭计时器,它也只会泄漏WeakWrap和计时器。理论上还是有内存泄漏的,但是比较少见。如果一个Controller频繁进出,一进一出,就丢了一个。如果主runloop上挂了几十个leakedtimer,会影响性能和流畅度。你觉得几十个两个定时器一起触发,调用定时器事件响应方法,开销还是蛮大的。已知方法3NSTimer强烈引用参数target:self。如果您忘记关闭计时器,则传入的任何内容都将被强引用。只需实现一个计时器。timer的作用就是定时调用某个方法。NSTimer的调用时间不准确!它挂在runloop上,受线程切换和上次事件执行时间的影响。使用dispatch_asyn()定期执行函数。请参阅下面的代码。-(void)loop{[selfdoSomething];......//稍作休息,调整循环实现定时调用[NSThreadsleepForTimeInterval:time];dispatch_async(self.runQueue,^{[weakSelfloop];});在}dispatch_async中调用循环不会产生递归调用。dispatch_async是在队列中添加一个task,GCD会回调[weakSelfloop]这个方法解决了timer无法释放的问题,在runloop中挂起无法移除。利用这个方法,我写了一个不会引起循环引用的定时器。当控制器松开时,定时器会自动停止松开。甚至self也可以直接写在timer的block中,不会出现循环引用。github下载地址方法四NSTimer循环引用的问题我以前从来没有遇到过,因为我一直都是成对使用,在viewWillAppear打开,在viewWillDisappear关闭。如果不关闭,runloop上挂载了那么多定时器,影响性能和流畅度。性,就像管理内存一样,申请和释放是成对使用的,所以不会有泄漏,谁申请谁释放的原则。但是在大团队的情况下,其他人可能会出错,造成泄密,这在技术上和团队编程规范上是可以解决的。比如设置一些规范,Controller退出的时候必须成功销毁,不能泄露内存。你不能在Block中写self等等。