AnsycDisplayKit源代碼分析

AsyncDisplayKit

AnsycDisplayKit是關注的人比較少的庫之一刽酱,這是因為這是個很重量級的庫朗恳,它基本重寫了UIKit罢防,使用它基本上就等同于放棄原來的UIView和UILayer的方案暑竟,還有個原因是很少有界面復雜到像Facebook那樣對體驗要求那么高。但這些問題都不影響我們探究它內(nèi)部的機制症概,畢竟這是個Facebook內(nèi)部使用的庫蕾额。
AnsycDisplayKit 的下載地址 https://github.com/facebookarchive/AsyncDisplayKit
正如github上所說,AsyncDisplayKit已經(jīng)重新命名為Texture 彼城,究其原因筆者猜測是因為作者(Scott Goodson)的離職诅蝶。他曾經(jīng)就職于Facebook以及Instagram等公司,并在這里大致介紹了AsyncDisplayKit 的概況 :
Scott Goodson - Behind AsyncDisplayKit
這個庫太龐大了募壕,以至于我們不可能在一篇文章中描述完全调炬,因此,筆者會做個系列博客和大家討論這個庫舱馅。本文的目錄如下:

git clone AnsycDisplayKit的代碼后我們進入example目錄缰泡,可以看到如下這么多目錄


AnsycDisplayKit的Example目錄

我們選中ASViewController并打開,然后在該目錄下pod update完成后即可運行運行程序代嗤,截圖如下:


截圖1

我們選中其中的任何一個(這里選中第一個)可以發(fā)現(xiàn):
截圖2

下面我們針對上面的兩張圖一一分析棘钞。
第一張圖是一個tableview列表頁(對應的Controller是ViewController),第二章是collectionview列表頁(對應的Controller是DetailViewController)干毅。

由代碼

@interface ViewController : ASViewController<ASTableNode *>
@end

可知宜猜,ViewController繼承自ASViewController。
當然硝逢,從代碼

@interface ASViewController<__covariant DisplayNodeType : ASDisplayNode *> : UIViewController <ASVisibilityDepth>
@end

顯而易見姨拥,ASViewController是UIViewController的一個子類。

在ViewController的初始化中趴捅,我們看到

- (instancetype)init
{
    self = [super initWithNode:[ASTableNode new]];
    if (self == nil) { return self; }
        
    return self;
}

因此垫毙,這里在ViewController的創(chuàng)建中霹疫,新建了一個ASTableNode拱绑。我們繼續(xù)看ASTableNode的代碼

@interface ASTableNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol>
@property (strong, nonatomic, readonly) ASTableView *view;
@end

顯而易見,Node與View的關系:


其中丽蝎,view是作為node的一個屬性存在猎拨,后面我們會發(fā)現(xiàn)膀藐,所有的針對UIKit層的操作,后面都是只針對ASNode的操作红省。那從view如何獲取node呢额各,這里先不做說明,后面的文章會有更加細致的說明吧恃。
總所周知虾啦,View和Layer是有很大聯(lián)系的,layer層負責UI的繪制痕寓,View負責事件的處理傲醉。所以我們不難得出如下的圖:



到這里,AsyncDisplayKit 的中心思想已經(jīng)介紹完了呻率。我們不難得出硬毕,在ViewController中如下代碼的大概意思

- (NSInteger)tableNode:(ASTableNode *)tableNode numberOfRowsInSection:(NSInteger)section
{
}
- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)tableNode:(ASTableNode *)tableNode didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
}

第一個的意思應該是cell的個數(shù)
第二個是每個cell的樣式
第三個是點擊cell的處理
那以前的UITableView的代理方法

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(nonnull NSIndexPath *)indexPath
{
}

<h1 id="2">2.ASDK的消息轉(zhuǎn)發(fā)機制</h1>
眾所周知,iOS的方法調(diào)用會經(jīng)歷三個階段:
消息轉(zhuǎn)發(fā)分為三大階段

  • 第一階段先征詢消息接收者所屬的類礼仗,看其是否能動態(tài)添加方法吐咳,以處理當前這個無法響應的 selector,這叫做 動態(tài)方法解析(dynamic method resolution)元践。如果運行期系統(tǒng)(runtime system) 第一階段執(zhí)行結(jié)束韭脊,接收者就無法再以動態(tài)新增方法的手段來響應消息,進入第二階段单旁。

  • 第二階段看看有沒有其他對象(備援接收者乾蓬,replacement receiver)能處理此消息。如果有慎恒,運行期系統(tǒng)會把消息轉(zhuǎn)發(fā)給那個對象任内,轉(zhuǎn)發(fā)過程結(jié)束;如果沒有融柬,則啟動完整的消息轉(zhuǎn)發(fā)機制死嗦。

  • 第三階段 完整的消息轉(zhuǎn)發(fā)機制。運行期系統(tǒng)會把與消息有關的全部細節(jié)都封裝到 NSInvocation 對象中粒氧,再給接收者最后一次機會越除,令其設法解決當前還未處理的消息。

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

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

Cat.m

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

看以上代碼摘盆,我們可以發(fā)現(xiàn),“貓”擁有說話的能力饱苟。
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的能力孩擂,沒有say的能力。
最后我們在ViewController中調(diào)用如下代碼:

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

我們會發(fā)現(xiàn)Pet也擁有了說話的能力箱熬。
這是因為Pet在調(diào)用say方法的時候發(fā)現(xiàn)找不到类垦,于是它去調(diào)用了methodSignatureForSelector方法狈邑。
這就是第二階段的含義。

我們?nèi)匀灰陨弦还?jié)的Demo為例蚤认,我們一一分析米苹。

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

這其實就是設置了tableview的delegate以及dataSource。并且還加入了自己的一些方法砰琢。這里我們以設置Delegate為例進行講解蘸嘶。

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

如圖,view.asyncDelegate = delegate;的詳細實現(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 {
//這里開始設置Delegate
    _asyncDelegate = asyncDelegate;
//這里插入了代理
    _proxyDelegate = [[ASTableViewProxy alloc] initWithTarget:_asyncDelegate interceptor:self];
    //這里用于判斷Delegate是否實現(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];

很關鍵,我們要注意ASTableViewProxy的實現(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

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

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
//設置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中能見到

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

等代碼的原因了

相關代碼

ProxyDemo

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末巡通,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子舍哄,更是在濱河造成了極大的恐慌宴凉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件表悬,死亡現(xiàn)場離奇詭異弥锄,居然都是意外死亡,警方通過查閱死者的電腦和手機蟆沫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門籽暇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人饭庞,你說我怎么就攤上這事戒悠。” “怎么了舟山?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵绸狐,是天一觀的道長。 經(jīng)常有香客問我累盗,道長寒矿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任若债,我火速辦了婚禮符相,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拆座。我一直安慰自己主巍,他們只是感情好,可當我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布挪凑。 她就那樣靜靜地躺著孕索,像睡著了一般。 火紅的嫁衣襯著肌膚如雪躏碳。 梳的紋絲不亂的頭發(fā)上搞旭,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音菇绵,去河邊找鬼肄渗。 笑死,一個胖子當著我的面吹牛咬最,可吹牛的內(nèi)容都是我干的翎嫡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼抛虫,長吁一口氣:“原來是場噩夢啊……” “哼权均!你這毒婦竟也來了歧寺?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤圈驼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后望几,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绩脆,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年橄抹,在試婚紗的時候發(fā)現(xiàn)自己被綠了靴迫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡楼誓,死狀恐怖矢劲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情慌随,我是刑警寧澤芬沉,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站阁猜,受9級特大地震影響丸逸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜剃袍,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一黄刚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧民效,春花似錦憔维、人聲如沸涛救。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽检吆。三九已至,卻和暖如春程储,著一層夾襖步出監(jiān)牢的瞬間蹭沛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工章鲤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留摊灭,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓败徊,卻偏偏與公主長得像帚呼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子皱蹦,可洞房花燭夜當晚...
    茶點故事閱讀 44,884評論 2 354

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