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
等代碼的原因了