NSTimer 循環(huán)引用

先來(lái)一個(gè)TimerDemo助助興绽乔。喲呵呵
定時(shí)器在項(xiàng)目開(kāi)發(fā)中會(huì)經(jīng)常使用,下邊就是最簡(jiǎn)單的一個(gè)定時(shí)器

@interface ViewController ()
// self 對(duì) timer 強(qiáng)引用
@property (nonatomic, strong) NSTimer *timer;
@end

- (void)viewDidLoad {
    [super viewDidLoad];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(test) userInfo:nil repeats:YES];
}
- (void)test {
    NSLog(@"%s", __func__);
}

循環(huán)引用原因

由于NSTimer會(huì)對(duì)target進(jìn)行強(qiáng)引用,這里我們傳入的target就是當(dāng)前控制器藏畅,然而當(dāng)前控制器self中我們定義了一個(gè)timer的指針來(lái)強(qiáng)引用了timer,所以這兩個(gè)對(duì)象就造成了循環(huán)引用跟衅,如下圖

在這里插入圖片描述

既然我們知道了循環(huán)引用的原因墨叛,那么我們就來(lái)解決一下這個(gè)循環(huán)引用問(wèn)題

解決方案一

我們嘗試讓NSTimer對(duì)target弱引用就行了唄殃恒。開(kāi)搞

// 讓 timer 對(duì)self 產(chǎn)生弱引用
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(test) userInfo:nil repeats:YES];

然并卵!S睾铩慕淡! 遺憾的是這個(gè)依然不能解決,原因就是當(dāng)我們使用__weakself轉(zhuǎn)為弱指針的時(shí)候沸毁,這個(gè)只有在Block變臉捕獲的時(shí)候才生效峰髓。所以這里我們應(yīng)該使用NSTimerblock方法。

    // 讓 timer 對(duì)self 產(chǎn)生弱引用
    __weak typeof(self) weakSelf = self;
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        [weakSelf test];
    }];

這次就可以成功了息尺。

解決方案二

既然兩個(gè)對(duì)象都對(duì)彼此強(qiáng)引用携兵,那么能不能找一個(gè)中間對(duì)象來(lái)解決這個(gè)問(wèn)題呢。如下圖

在這里插入圖片描述

如圖所示VC對(duì)Timer是強(qiáng)引用掷倔,Timer對(duì)中間對(duì)象強(qiáng)引用眉孩,中間對(duì)象對(duì)VC產(chǎn)生弱引用。這也可以解決循環(huán)引用的問(wèn)題勒葱。接下來(lái)就是我們需要?jiǎng)?chuàng)建一個(gè)中間對(duì)象浪汪,讓他對(duì)VC產(chǎn)生弱引用。

.h
@interface DDWeakObject : NSObject
/// 創(chuàng)建一個(gè)過(guò)渡類 讓NSTimer 或者  CADisplayLink 對(duì)這個(gè)類產(chǎn)生弱引用 解決循環(huán)引用的問(wèn)題
/// @param target 產(chǎn)生循環(huán)引用的target
+ (instancetype)weakObjectWithTarget:(id)target;
@end

.m
#import "DDWeakObject.h"

@interface DDWeakObject()
@property (weak, nonatomic) id target;
@end

@implementation DDWeakObject
+(instancetype)weakObjectWithTarget:(id)target {
    DDWeakObject *weakObject = [[DDWeakObject alloc] init];
    weakObject.target = target;
    return weakObject;
}

// 利用消息轉(zhuǎn)發(fā)機(jī)制 讓這個(gè)類調(diào)用 target 的 方法
- (id)forwardingTargetForSelector:(SEL)aSelector {
    return self.target;
}

@end

我們?cè)?code>.m文件中定義一個(gè)target,讓這個(gè)自定義對(duì)象對(duì)target產(chǎn)生弱引用凛虽,所以我們使用weak修飾target這個(gè)屬性死遭。我們這里使用消息轉(zhuǎn)發(fā)機(jī)制,讓該對(duì)象去響應(yīng)target的方法凯旋,有關(guān)消息轉(zhuǎn)發(fā)機(jī)制問(wèn)題呀潭,請(qǐng)?jiān)L問(wèn)我的另一篇文章 OC方法調(diào)用流程

// 當(dāng)前VC強(qiáng)引用了 timer
    // timer 對(duì) weakObject 強(qiáng)引用
    // 但是 weakObject 對(duì) self 是弱引用的關(guān)系
    // 因此不會(huì)產(chǎn)生循環(huán)引用
    DDWeakObject *weakObject = [DDWeakObject weakObjectWithTarget:self];
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakObject selector:@selector(test) userInfo:nil repeats:YES];

解決方案三

我們根據(jù)方案二钉迷,我們延伸出了NSProxy這個(gè)類,這個(gè)類跟NSObject一樣是一個(gè)基類钠署。專門處理這種交換的糠聪,好比一個(gè)中間橋梁。使用跟方案二差不多谐鼎。

.h
@interface DDProxy : NSProxy
+ (instancetype)proxyWithTarget:(id)target;
@end

.m
@interface DDProxy()
@property (weak, nonatomic) id target;
@end

@implementation DDProxy
+ (instancetype)proxyWithTarget:(id)target {
    DDProxy *proxy = [DDProxy alloc];
    proxy.target = target;
    return  proxy;
}

// 以下還是運(yùn)用消息轉(zhuǎn)發(fā)機(jī)制進(jìn)行
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
    return [self.target methodSignatureForSelector:sel];
}

-(void)forwardInvocation:(NSInvocation *)invocation {
    [invocation invokeWithTarget:self.target];
}
@end

與方案二的不同點(diǎn)在于舰蟆,消息轉(zhuǎn)發(fā)時(shí)機(jī)不一樣,這里使用了是方法簽名狸棍。優(yōu)點(diǎn)在于NDProxy效率比方案二更高身害。

好了解決NSTimer定時(shí)器循環(huán)引用的方法已經(jīng)完成。后面兩個(gè)方案也可以解決CADisplayLink 產(chǎn)生的循環(huán)引用問(wèn)題草戈。因?yàn)?code>CADisplayLink同樣是對(duì)target進(jìn)行了強(qiáng)引用塌鸯。這里我不在贅述。

最后附上TimerDemo唐片,覺(jué)得不錯(cuò)的丙猬,記得Star喲!

OK牵触,完結(jié)撒花???? 大家加油;吹俊!揽思!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末袜腥,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子钉汗,更是在濱河造成了極大的恐慌羹令,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件损痰,死亡現(xiàn)場(chǎng)離奇詭異福侈,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)卢未,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門肪凛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人辽社,你說(shuō)我怎么就攤上這事伟墙。” “怎么了滴铅?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵戳葵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我汉匙,道長(zhǎng)拱烁,這世上最難降的妖魔是什么生蚁? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮戏自,結(jié)果婚禮上邦投,老公的妹妹穿的比我還像新娘。我一直安慰自己擅笔,他們只是感情好尼摹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著剂娄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪玄呛。 梳的紋絲不亂的頭發(fā)上阅懦,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音徘铝,去河邊找鬼耳胎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惕它,可吹牛的內(nèi)容都是我干的怕午。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼淹魄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼郁惜!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起甲锡,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兆蕉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后缤沦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體虎韵,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年缸废,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了包蓝。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡企量,死狀恐怖测萎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梁钾,我是刑警寧澤绳泉,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站姆泻,受9級(jí)特大地震影響零酪,放射性物質(zhì)發(fā)生泄漏冒嫡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一四苇、第九天 我趴在偏房一處隱蔽的房頂上張望孝凌。 院中可真熱鬧,春花似錦月腋、人聲如沸蟀架。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)片拍。三九已至,卻和暖如春妓肢,著一層夾襖步出監(jiān)牢的瞬間捌省,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工碉钠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纲缓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓喊废,卻偏偏與公主長(zhǎng)得像祝高,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子污筷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容