Node Containers

ASViewController

ASViewControllerUIViewController的子类,添加了一些有用的功能来承载ASDisplayNode层次结构
可以使用ASViewController代替任何UIViewControlller

使用ASViewController的好处:

  1. 保存内存。
  2. ASVisibility

使用

UIViewController提供了自己的View。ASViewController在初始化时 通过initWithNode分配了要管理的节点

//例如 修改视图控制器的视图的根node 为 table node

- (instancetype)init
{
  _tableNode = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
  self = [super initWithNode:_tableNode];
  
  if (self) {
    _tableNode.dataSource = self;
    _tableNode.delegate = self;
  }
  
  return self;
}

ASTableNode

相当于UITableView 并且可以用来代替任何UITableView

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

//替换方法
- (ASCellNode *)tableNode:(ASTableNode *)tableNode nodeForRowAtIndexPath:(NSIndexPath *)indexPath
//或者
- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath

建议使用 nodeblock版本,以便table node可以同时准备和display。这意味着所有的subnode初始化方法都会在后台运行,请确保线程安全。

ASCellNodeBlock是创建ASCellNode的block,能够在后台线程运行。

注意

ASCellNodesASTableNode、ASCollectionNode、ASPagerNode使用

这些方法均不需要重用机制(只会执行一次,与UIKIt不同,当行要显示时不会调用这些方法)

node block的线程安全

node blocks必须是线程安全的。一方面是确保在node block外访问数据模型。因此,不太需要会在block内部访问indexPath

- (ASCellNodeBlock)tableNode:(ASTableNode *)tableNode nodeBlockForRowAtIndexPath:(NSIndexPath *)indexPath
{
    PhotoModel *photoModel = [_photoFeed objectAtIndex:indexPath.row];
    
    // this may be executed on a background thread - it is important to make sure it is thread safe
    ASCellNode *(^cellNodeBlock)() = ^ASCellNode *() {
        PhotoCellNode *cellNode = [[PhotoCellNode alloc] initWithPhoto:photoModel];
        cellNode.delegate = self;
        return cellNode;
    };
    
    return cellNodeBlock;
}

ASTableView的访问

ASTableViewUITalbeView的子类,在ASTalbeNode内部进行使用,可以在viewDidLoaddidLoad方法找中通过.view属性访问节点的view或者layer属性

例如,可以再ViewDidLoad方法中 访问呢表节点的视图完成对表格的分隔符样式设置

- (void)viewDidLoad
{
  [super viewDidLoad];
  
  _tableNode.view.allowsSelection = NO;
  _tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone;
  _tableNode.view.leadingScreensForBatching = 3.0;  // default is 2.0
}

行高

需要注意的是: ASTableNode不提供和UITableViewtableView:heightForRowAtIndexPath等效功能
这是因为node 会根据提供的约束确定其自身的高度,因此不再需要编写代码在视图控制器中确定此信息
node通过layoutSpecThatFits方法 返回的layoutSpec定义其高度。所有给定了限制size的node都可以计算其目标size

默认情况,ASTableNode给其cell提供的大小范围约束,其中最小宽度为tablenode的宽度,最小高度为0.最大宽度为tablenode的宽度,最大高度为FLT_MAX,就是说table的cell宽度是固定的为整个table的宽度,但是其高度时灵活的,可以自动调整大小

如果在ASCellNode上调用-setNeddsLayout 将自动执行一遍布局,如果总体所需大小已经更改,通知table 将会进行更新

注意

这些规则和UIKit不同,在UIKit中必须调用reload row/item。这样就节省了大量代码

ASCollectionNode

ASCollectionNode 等效于 UICollectionView 可以在任何情况下替代UICollectionView

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;
//替换为
- (ASCellNode *)collectionNode:(ASCollectionNode *)collectionNode nodeForItemAtIndexPath:(NSIndexPath *)indexPath
//或
- (ASCellNodeBlock)collectionNode:(ASCollectionNode *)collectionNode nodeBlockForItemAtIndexPath:(NSIndexPath *)indexPath

推荐使用node block

cell 大小和布局

可以使用ASCollectionNode-constrainedSizeForItemAtIndexPath:约束colletion node中使用的cell

UICollectionViewCell的互通性

ASCollectionNode支持UICollectionViewCellsASCellNodes一起使用

注意:即使混合在统一ASCollectionNode中,这些UIKit组件也不会有ASCellNode的性能优势

ASPageNode

ASPageNodeASCollectionView的子类,只是内部采用了特殊的UIColelctionViewLayout

ASPageNode可以创建出类似UIPageViewController创建的页面UI。支持在轮换期间停留在正确的页面。不支持循环滚动

- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode
//和
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
//或者
- (ASCellNodeBlock)pagerNode:(ASPagerNode *)pagerNode nodeBlockAtIndex:(NSInteger)index`

使用ASViewController来获得最佳性能

一种特别有用的模式就是 返回 使用现有UIViewController或者ASViewController初始化的ASCellNode。当然,为了获得最佳性能请使用ASViewController

- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index
{
    NSArray *animals = self.animals[index];
    
    ASCellNode *node = [[ASCellNode alloc] initWithViewControllerBlock:^{
        return [[AnimalTableNodeController alloc] initWithAnimals:animals];;
    } didLoadBlock:nil];
    
    node.style.preferredSize = pagerNode.bounds.size;
    
    return node;
}

在这个例子中,该节点使用initWithViewControllerBlock:方法构造。通常时必须采用这种方法,以便执行正确的布局

使用ASPagerNode作为ASViewController的root node

log message