AnsycDisplayKit源代碼分析2:關(guān)于NSProxy

AsyncDisplayKit

AnsycDisplayKit是關(guān)注的人比較少的庫(kù)之一,這是因?yàn)檫@是個(gè)很重量級(jí)的庫(kù),它基本重寫了UIKit,使用它基本上就等同于放棄原來(lái)的UIView和UILayer的方案磕道,還有個(gè)原因是很少有界面復(fù)雜到像Facebook那樣對(duì)體驗(yàn)要求那么高。但這些問(wèn)題都不影響我們探究它內(nèi)部的機(jī)制行冰,畢竟這是個(gè)Facebook內(nèi)部使用的庫(kù)溺蕉。
AnsycDisplayKit 的下載地址 https://github.com/facebookarchive/AsyncDisplayKit
正如github上所說(shuō),AsyncDisplayKit已經(jīng)重新命名為Texture 悼做,究其原因筆者猜測(cè)是因?yàn)樽髡撸⊿cott Goodson)的離職疯特。他曾經(jīng)就職于Facebook以及Instagram等公司,并在這里大致介紹了AsyncDisplayKit 的概況 :
Scott Goodson - Behind AsyncDisplayKit
這個(gè)庫(kù)太龐大了肛走,以至于我們不可能在一篇文章中描述完全漓雅,因此,筆者會(huì)做個(gè)系列博客和大家討論這個(gè)庫(kù)朽色。今天我們講第2篇:關(guān)于NSProxy
本文的知識(shí)點(diǎn):

  • iOS中的消息轉(zhuǎn)發(fā)機(jī)制
  • 多繼承
  • AOP

眾所周知邻吞,iOS的方法調(diào)用會(huì)經(jīng)歷三個(gè)階段:
消息轉(zhuǎn)發(fā)分為三大階段

  • 第一階段先征詢消息接收者所屬的類,看其是否能動(dòng)態(tài)添加方法葫男,以處理當(dāng)前這個(gè)無(wú)法響應(yīng)的 selector抱冷,這叫做 動(dòng)態(tài)方法解析(dynamic method resolution)。如果運(yùn)行期系統(tǒng)(runtime system) 第一階段執(zhí)行結(jié)束腾誉,接收者就無(wú)法再以動(dòng)態(tài)新增方法的手段來(lái)響應(yīng)消息徘层,進(jìn)入第二階段。
  • 第二階段看看有沒(méi)有其他對(duì)象(備援接收者利职,replacement receiver)能處理此消息趣效。如果有,運(yùn)行期系統(tǒng)會(huì)把消息轉(zhuǎn)發(fā)給那個(gè)對(duì)象猪贪,轉(zhuǎn)發(fā)過(guò)程結(jié)束跷敬;如果沒(méi)有,則啟動(dòng)完整的消息轉(zhuǎn)發(fā)機(jī)制热押。
  • 第三階段 完整的消息轉(zhuǎn)發(fā)機(jī)制西傀。運(yùn)行期系統(tǒng)會(huì)把與消息有關(guān)的全部細(xì)節(jié)都封裝到 NSInvocation 對(duì)象中,再給接收者最后一次機(jī)會(huì)桶癣,令其設(shè)法解決當(dāng)前還未處理的消息拥褂。

我們就在第二階段進(jìn)行插入代理者的操作,代碼如下所示(其中Animal是繼承自NSObject的類)
Cat.h

@interface Cat : Animal
-(void)say;
@end

Cat.m

@implementation Cat
-(void)say
{
    NSLog(@"miao");
}
@end

看以上代碼牙寞,我們可以發(fā)現(xiàn)饺鹃,“貓”擁有說(shuō)話的能力。
Pet.h

@interface Pet : NSObject
@property (nonatomic, strong) NSObject *intercetper;
-(void) play;
@end

Pet.m

@implementation Pet
-(void) play{
    NSLog(@"pay");
}

-(void)forwardInvocation:(NSInvocation *)invocation
{
    [invocation setTarget:self.intercetper];
    [invocation invoke];
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
{
    NSMethodSignature *signature = nil;
    if ([self.intercetper methodSignatureForSelector:sel]) {
        signature = [self.intercetper methodSignatureForSelector:sel];
    }else{
        signature = [self methodSignatureForSelector:sel];
    }
    return signature;
}
@end

由Pet的代碼可知Pet只有Play的能力间雀,沒(méi)有say的能力悔详。
最后我們?cè)赩iewController中調(diào)用如下代碼:

Cat *cat = [[Cat alloc] init];
Pet *pet = [[Pet alloc] init];
pet.intercetper = cat;
[pet performSelector:@selector(say) withObject:nil];

我們會(huì)發(fā)現(xiàn)Pet也擁有了說(shuō)話的能力。
這是因?yàn)镻et在調(diào)用say方法的時(shí)候發(fā)現(xiàn)找不到惹挟,于是它去調(diào)用了methodSignatureForSelector方法茄螃。
這就是第二階段的含義。

我們?nèi)匀灰陨弦黄腄emo為例连锯,我們一一分析归苍。

- (void)viewDidLoad
{
    [super viewDidLoad];
    self.title = @"Image Categories";
    self.node.delegate = self;
    self.node.dataSource = self;
}

這其實(shí)就是設(shè)置了tableview的delegate以及dataSource。并且還加入了自己的一些方法运怖。這里我們以設(shè)置Delegate為例進(jìn)行講解霜医。

- (void)setDelegate:(id <ASTableDelegate>)delegate
{
  if ([self pendingState]) {
    _pendingState.delegate = delegate;
  } else {
//這里獲取TableView
    ASTableView *view = self.view;
//這里設(shè)置Delegate
    ASPerformBlockOnMainThread(^{
      view.asyncDelegate = delegate;
    });
  }
}

如圖,view.asyncDelegate = delegate;的詳細(xì)實(shí)現(xiàn)如下

- (void)setAsyncDelegate:(id<ASTableDelegate>)asyncDelegate
{
  ASDisplayNodeAssertMainThread();
  NS_VALID_UNTIL_END_OF_SCOPE id oldDelegate = super.delegate;
  //如果是置空驳规,則表明是要釋放delegate
  if (asyncDelegate == nil) {
    _asyncDelegate = nil;
    _proxyDelegate = _isDeallocating ? nil : [[ASTableViewProxy alloc] initWithTarget:nil interceptor:self];
    memset(&_asyncDelegateFlags, 0, sizeof(_asyncDelegateFlags));
  } else {
//這里開始設(shè)置Delegate
    _asyncDelegate = asyncDelegate;
//這里插入了代理
    _proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
    //這里用于判斷Delegate是否實(shí)現(xiàn)了如下方法肴敛。
    _asyncDelegateFlags.scrollViewDidScroll = [_asyncDelegate respondsToSelector:@selector(scrollViewDidScroll:)];
    _asyncDelegateFlags.tableViewWillDisplayNodeForRow = [_asyncDelegate respondsToSelector:@selector(tableView:willDisplayNode:forRowAtIndexPath:)];
    _asyncDelegateFlags.tableNodeWillDisplayNodeForRow = [_asyncDelegate respondsToSelector:@selector(tableNode:willDisplayRowWithNode:)];
//這里省略一大段類似的代碼
  }
  super.delegate = (id<UITableViewDelegate>)_proxyDelegate;
}

其中

 _proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];

很關(guān)鍵,我們要注意ASTableViewProxy的實(shí)現(xiàn)

- (BOOL)interceptsSelector:(SEL)selector
{
  return (
          // handled by ASTableView node<->cell machinery
          selector == @selector(tableView:cellForRowAtIndexPath:) ||
          selector == @selector(tableView:heightForRowAtIndexPath:) 
//這里省略一大段類似的代碼
            );
}

@end

interceptsSelector指的就是需要攔截的方法吗购,并且攔截的方法要被ASTableview使用医男。因此,我們能在ASTableview中發(fā)現(xiàn)如下代碼:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath

而他們的實(shí)現(xiàn)如下:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//設(shè)置cell
  _ASTableViewCell *cell = [self dequeueReusableCellWithIdentifier:kCellReuseIdentifier forIndexPath:indexPath];
  cell.delegate = self;
//創(chuàng)建自己的Node
  ASCellNode *node = [_dataController.visibleMap elementForItemAtIndexPath:indexPath].node;
  if (node) {
    [_rangeController configureContentView:cell.contentView forCellNode:node];
    cell.node = node;
  }
  return cell;
}

看到這里捻勉,想必大家知道為什么在ViewController中能見(jiàn)到

- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath

等代碼的原因了

相關(guān)代碼

ProxyDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末镀梭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子踱启,更是在濱河造成了極大的恐慌报账,老刑警劉巖研底,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異透罢,居然都是意外死亡榜晦,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門羽圃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)乾胶,“玉大人,你說(shuō)我怎么就攤上這事朽寞∈读” “怎么了?”我有些...
    開封第一講書人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵脑融,是天一觀的道長(zhǎng)喻频。 經(jīng)常有香客問(wèn)我,道長(zhǎng)肘迎,這世上最難降的妖魔是什么半抱? 我笑而不...
    開封第一講書人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮膜宋,結(jié)果婚禮上窿侈,老公的妹妹穿的比我還像新娘。我一直安慰自己秋茫,他們只是感情好史简,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肛著,像睡著了一般圆兵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枢贿,一...
    開封第一講書人閱讀 50,043評(píng)論 1 291
  • 那天殉农,我揣著相機(jī)與錄音,去河邊找鬼局荚。 笑死超凳,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的耀态。 我是一名探鬼主播轮傍,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼首装!你這毒婦竟也來(lái)了创夜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎偏化,沒(méi)想到半個(gè)月后戒傻,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姐呐,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年徒欣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吟孙。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俐末。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡偎蘸,死狀恐怖庄蹋,靈堂內(nèi)的尸體忽然破棺而出瞬内,到底是詐尸還是另有隱情迷雪,我是刑警寧澤,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布虫蝶,位于F島的核電站章咧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏能真。R本人自食惡果不足惜赁严,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粉铐。 院中可真熱鬧疼约,春花似錦、人聲如沸蝙泼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)汤踏。三九已至织鲸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間溪胶,已是汗流浹背搂擦。 一陣腳步聲響...
    開封第一講書人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留哗脖,地道東北人瀑踢。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像才避,于是被迫代替她去往敵國(guó)和親丘损。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

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