国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > iOS > 正文

iOS開發(fā)筆記之六十三——一個(gè)NSTimer引發(fā)內(nèi)存泄漏

2019-11-08 00:05:21
字體:
供稿:網(wǎng)友

一、問題產(chǎn)生與分析

先看下產(chǎn)生的代碼:

- (void)dealloc{    [self.timer invalidate];    self.timer = nil;    NSLog(@"dealloc!!!!!!!");}- (void)viewDidLoad{    [super viewDidLoad];    self.timer = [NSTimer scheduledTimerWithTimeInterval:3.0f                                                  target:self                                                selector:@selector(timerFire)                                                userInfo:nil                                                 repeats:YES];    [self.timer fire];}- (void)timerFire{    NSLog(@"fire");}

在這段代碼,你在dealloc處放置一個(gè)breakpoint,你會(huì)發(fā)現(xiàn)dealloc方法不會(huì)執(zhí)行的。因?yàn)榇藭r(shí)存在著一個(gè)引用循環(huán):

每個(gè)NSTimer其實(shí)是被添加在所在線程的runloop中,而runloop對(duì)timer是一種強(qiáng)持有關(guān)系,看下蘋果官網(wǎng):

也就是說,此時(shí)的timer采取strong PRoperty的方式其實(shí)是不合理的。那么為什么Runloop要strong reference to a timer呢,首先,NSTimer的執(zhí)行需要加到runloop中去。RunLoop有一個(gè)CFRunLoopTimerRef 是基于時(shí)間的觸發(fā)器的類,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一個(gè)時(shí)間長度和一個(gè)回調(diào)(函數(shù)指針)。當(dāng)其加入到 RunLoop 時(shí),RunLoop會(huì)注冊(cè)對(duì)應(yīng)的時(shí)間點(diǎn),當(dāng)時(shí)間點(diǎn)到時(shí),RunLoop會(huì)被喚醒以執(zhí)行那個(gè)回調(diào)(這就是為什么要強(qiáng)持有target)。

二、解決方法

1、及時(shí)invalidate()掉Timer

invalidate()的作用,蘋果有描述 :

執(zhí)行之后,Runloop對(duì)Timer的強(qiáng)引用就會(huì)remove掉,同時(shí)timer對(duì)target的強(qiáng)引用也會(huì)remove掉,通過CFGetRetainCount()方法查看self的引用即可知道,驗(yàn)證如下:

NO Repeats的Timer是會(huì)自動(dòng)invalidate()的,所以,invalidate()后timer僅僅是self的一個(gè)屬性變量了。

對(duì)于Repeats類型的Timer需要在合適的時(shí)機(jī)去手動(dòng)invalidate()了,例如在viewDidDisappear方法中,就是一種不錯(cuò)的嘗試。

2、不需要手動(dòng)設(shè)置NSTimer為invalid 的方法:造一個(gè)假的target給NSTimer,假的target作用就是用于接受NSTimer的強(qiáng)引用。

具體的思路代碼,如下:

[...]@implementation NSWeakTimerTarget{    __weak target;    SEL selector;}[...] - (void)timerDidFire:(NSTimer *)timer{    if (target)    {        [target performeSelector:selector withObject:timer];    }    else    {        [timer invalidate];    }}@end @implementation NSWeakTimer    + (NSTimer *)scheduledTimerWithTimerInterval:(NSTimeInterval)ti target:(id)target selector:(SEL)aSelector userInfo:(id)userInfo repeat:(BOOL)repeats{    NSWeakTimerTarget *timerTarget = [[NSWeakTimerTarget alloc] init]    timerTarget.target = aTarget;    timerTarget.selector = aSelector;    timerTarget.timer = [NSTimer scheduledTimerWithTimeInterval:ti target:timerTarget selector:@selector(timerDidFire:) userInfo: userInfo repeats: repeats];    return timerTarget.timer;}@end此法真正的target并不會(huì)被timer 持有,當(dāng)真正的target為空的時(shí)候,timer會(huì)執(zhí)行invalid。此法的github地址:https://github.com/ChatGame/HWWeakTimer

三、參考資料

1、https://developer.apple.com/reference/foundation/timer/1415405-invalidate?changes=latest_minor

2、http://www.jianshu.com/p/f9999b5958f8


發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 台南市| 锦屏县| 卢湾区| 正安县| 科技| 广丰县| 肥西县| 环江| 济源市| 宜宾市| 嘉黎县| 平罗县| 绥芬河市| 互助| 卢龙县| 平武县| 腾冲县| 米泉市| 玉门市| 凌云县| 仁寿县| 海宁市| 玛曲县| 永春县| 德昌县| 乌审旗| 宜兰县| 紫阳县| 庐江县| 平利县| 门源| 拜城县| 达拉特旗| 上林县| 昭平县| 卢氏县| 米脂县| 永泰县| 拜泉县| 伊宁市| 海安县|