weakProxy

前言

NSProxy是iOS開發(fā)中一個(gè)消息轉(zhuǎn)發(fā)的基類阔馋,它不繼承自NSObject。因?yàn)檫@個(gè)類不太常用苛败,所以對于很多開發(fā)者來說根本沒有用過它缰犁。

不過,這個(gè)類對于iOS開發(fā)還是很有用的捡偏。本文首先會(huì)講解下這個(gè)類的基礎(chǔ)唤冈,然后講解下消息轉(zhuǎn)發(fā)機(jī)制,因?yàn)槲矣X得不懂消息轉(zhuǎn)發(fā)機(jī)制银伟,很難理解更深層次的東西你虹,最后通過一個(gè)實(shí)例來講解下NSProxy的實(shí)際應(yīng)用。

NSProxy

NSProxy本身是一個(gè)抽象類彤避,它遵循NSObject協(xié)議傅物,提供了消息轉(zhuǎn)發(fā)的通用接口。NSProxy通常用來實(shí)現(xiàn)消息轉(zhuǎn)發(fā)機(jī)制和惰性初始化資源琉预。

使用NSProxy董饰,你需要寫一個(gè)子類繼承它,然后需要實(shí)現(xiàn)init以及消息轉(zhuǎn)發(fā)的相關(guān)方法圆米。

//當(dāng)一個(gè)消息轉(zhuǎn)發(fā)的動(dòng)作NSInvocation到來的時(shí)候卒暂,在這里選擇把消息轉(zhuǎn)發(fā)給對應(yīng)的實(shí)際處理對象-(void)forwardInvocation:(NSInvocation*)anInvocation//當(dāng)一個(gè)SEL到來的時(shí)候,在這里返回SEL對應(yīng)的NSMethodSignature -(NSMethodSignature*)methodSignatureForSelector:(SEL)aSelector //是否響應(yīng)一個(gè)SEL +(BOOL)respondsToSelector:(SEL)aSelector

為什么OC中要繼承NSObject而Swift中不用娄帖?

很簡答也祠,Objective C是一個(gè)強(qiáng)烈依賴運(yùn)行時(shí)(Runtime)的一門語言。

你可以利用Runtime來做到很多東西近速,比如方法替換诈嘿,交叉堪旧,屬性添加等等。

但是奖亚,你有沒有想過淳梦,大多數(shù)時(shí)候你并沒有寫任何代碼來支持Runtime,iOS如何知道這些runtime的信息呢昔字?

這就是繼承自NSObject的意義所在

繼承自NSObject之后爆袍,你的所有的類其實(shí)都默認(rèn)實(shí)現(xiàn)了NSObject的許多Runtime相關(guān)方法。

+initialize//在一個(gè)類接收第一條消息之前的+load//在一個(gè)類對象加載到Runtime的時(shí)候調(diào)用

//檢查是否可以向?qū)嵙ο蟀l(fā)送某消息+(BOOL)instancesRespondToSelector:(SEL)aSelector-respondsToSelector:

//向?qū)ο蟀l(fā)送消息-(id)performSelector:(SEL)aSelector-performSelector:withObject:-performSelector:withObject:withObject:...

//動(dòng)態(tài)消息轉(zhuǎn)發(fā)處理機(jī)制+resolveInstanceMethod:-forwardingTargetForSelector:-forwardInvocation:

而Swift不用李滴,Swift中螃宙,非繼承自NSObject的類是靜態(tài)分發(fā)(static dispatch)的,它用的原理是類似C++中的虛表所坯。

簡單來說谆扎,就是在編譯期間,一個(gè)方法的調(diào)用就被編譯成調(diào)用一個(gè)地址了芹助,無法動(dòng)態(tài)修改堂湖。

消息轉(zhuǎn)發(fā)機(jī)制

我們都都知道,對于Objective C來說状土,一個(gè)方法的調(diào)用本質(zhì)上是一個(gè)消息的發(fā)送无蜂。然后Runtime沿著當(dāng)前類的isa,然后逐步的向基類找方法的實(shí)現(xiàn)蒙谓,如果到NSObject還未實(shí)現(xiàn)對應(yīng)的方法斥季,則會(huì)拋出異常。

對于Runtime不熟悉的同學(xué)累驮,可以看看我之前的這篇博客酣倾。

其實(shí),在拋出異常之前谤专,Runtime仍然為我們提供一種機(jī)制躁锡,來處理當(dāng)前對象無法響應(yīng)的方法-消息轉(zhuǎn)發(fā)。

消息轉(zhuǎn)發(fā)涉及到三個(gè)核心方法

//消息轉(zhuǎn)發(fā)第一步置侍,在這里可以動(dòng)態(tài)的為類添加方法映之,這樣類自己就能處理了+resolveInstanceMethod://消息轉(zhuǎn)發(fā)第二步,在第一步無法完成的情況下執(zhí)行蜡坊。這里只是把一個(gè)Selector簡單的轉(zhuǎn)發(fā)給另一個(gè)對象- forwardingTargetForSelector://消息轉(zhuǎn)發(fā)第三步杠输,在第二步也無法完成的情況下執(zhí)行。將整個(gè)消息封裝成NSInvocation秕衙,傳遞下去- forwardInvocation:

消息轉(zhuǎn)發(fā)機(jī)制使得代碼變的很靈活:一個(gè)類本身可以完全不實(shí)現(xiàn)某些方法抬伺,它只要能轉(zhuǎn)發(fā)就可以了。

一個(gè)例子灾梦,破循環(huán)引用

NSTimer是一個(gè)需要添加到Runloop里的類峡钓,對于一個(gè)不會(huì)自動(dòng)停止的Timer,你需要調(diào)用invalidate方法來手動(dòng)斷開這個(gè)Timer若河。否則能岩,引用Timer的Controller或者其他類,就會(huì)出現(xiàn)循環(huán)引用而無法釋放掉萧福。

舉個(gè)例子,在Controller中拉鹃,添加Timer很常見,比如

#import"SecondViewController.h"@interfaceSecondViewController()@property(strong,nonatomic)NSTimer * timer;@end@implementationSecondViewController- (void)viewDidLoad{? ? [superviewDidLoad];self.timer= [NSTimer timerWithTimeInterval:1target:selfselector:@selector(timerInvoked:)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? userInfo:nilrepeats:YES];? ? [[NSRunLoop mainRunLoop] addTimer:self.timerforMode:NSRunLoopCommonModes];}- (void)timerInvoked:(NSTimer *)timer{NSLog(@"1");}- (void)dealloc{NSLog(@"Dealloc");}@end

假如我Push這樣一個(gè)SecondViewController,然后pop鲫忍。

你會(huì)發(fā)現(xiàn)Controller沒有被釋放膏燕,timer也沒有被取消。

我們可以在dealloc中悟民,調(diào)用Timer取消嗎坝辫?比如

- (void)dealloc{? ? [self.timerinvalidate];NSLog(@"Dealloc");}

當(dāng)然不行,因?yàn)镃ontroller根本沒有被釋放射亏,dealloc方法根本不會(huì)調(diào)用近忙。

當(dāng)然,破壞這種循環(huán)引用的方式有很多種智润。本文主要講解如何用NSProxy來破壞及舍。

我們寫一個(gè)WeakProxy來實(shí)現(xiàn)弱引用

@interfaceWeakProxy:NSProxy@property(weak,nonatomic,readonly)idtarget;+ (instancetype)proxyWithTarget:(id)target;- (instancetype)initWithTarget:(id)target;@end@implementationWeakProxy- (instancetype)initWithTarget:(id)target{? ? _target = target;returnself;}+ (instancetype)proxyWithTarget:(id)target{return[[selfalloc] initWithTarget:target];}- (void)forwardInvocation:(NSInvocation *)invocation{? ? SEL sel = [invocation selector];if([self.targetrespondsToSelector:sel]) {? ? ? ? [invocation invokeWithTarget:self.target];? ? }}- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{return[self.targetmethodSignatureForSelector:aSelector];}- (BOOL)respondsToSelector:(SEL)aSelector{return[self.targetrespondsToSelector:aSelector];}@end

然后,這樣創(chuàng)建Timer窟绷,

self.timer= [NSTimer timerWithTimeInterval:1target:[WeakProxy proxyWithTarget:self]? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? selector:@selector(timerInvoked:)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? userInfo:nilrepeats:YES];

你會(huì)發(fā)現(xiàn)可以釋放了锯玛。

原理如下:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市兼蜈,隨后出現(xiàn)的幾起案子攘残,更是在濱河造成了極大的恐慌,老刑警劉巖饭尝,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肯腕,死亡現(xiàn)場離奇詭異,居然都是意外死亡钥平,警方通過查閱死者的電腦和手機(jī)实撒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來涉瘾,“玉大人知态,你說我怎么就攤上這事×⑴眩” “怎么了负敏?”我有些...
    開封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秘蛇。 經(jīng)常有香客問我其做,道長顶考,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任妖泄,我火速辦了婚禮驹沿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蹈胡。我一直安慰自己渊季,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開白布罚渐。 她就那樣靜靜地躺著却汉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪荷并。 梳的紋絲不亂的頭發(fā)上合砂,一...
    開封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音璧坟,去河邊找鬼既穆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛雀鹃,可吹牛的內(nèi)容都是我干的幻工。 我是一名探鬼主播,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼黎茎,長吁一口氣:“原來是場噩夢啊……” “哼囊颅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起傅瞻,我...
    開封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬榮一對情侶失蹤踢代,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后嗅骄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胳挎,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年溺森,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了慕爬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡屏积,死狀恐怖医窿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情炊林,我是刑警寧澤姥卢,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響独榴,放射性物質(zhì)發(fā)生泄漏僧叉。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一括眠、第九天 我趴在偏房一處隱蔽的房頂上張望彪标。 院中可真熱鬧,春花似錦掷豺、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至默辨,卻和暖如春德频,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背缩幸。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來泰國打工壹置, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人表谊。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓钞护,卻偏偏與公主長得像,于是被迫代替她去往敵國和親爆办。 傳聞我的和親對象是個(gè)殘疾皇子难咕,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,735評(píng)論 0 9
  • 參考鏈接: http://www.cnblogs.com/ioshe/p/5489086.html 簡介 Runt...
    樂樂的簡書閱讀 2,138評(píng)論 0 9
  • 我們常常會(huì)聽說 Objective-C 是一門動(dòng)態(tài)語言距辆,那么這個(gè)「動(dòng)態(tài)」表現(xiàn)在哪呢余佃?我想最主要的表現(xiàn)就是 Obje...
    Ethan_Struggle閱讀 2,199評(píng)論 0 7
  • 轉(zhuǎn)載:http://yulingtianxia.com/blog/2014/11/05/objective-c-r...
    F麥子閱讀 736評(píng)論 0 2
  • 本文轉(zhuǎn)載自:http://yulingtianxia.com/blog/2014/11/05/objective-...
    ant_flex閱讀 767評(píng)論 0 1