项目调优

IOS中使用AsynDisplayKit优化项目

2018-03-20  本文已影响65人  寻找最亮的光

前言

在学习别人文章的时候做一个记录,免得在需要的时候找不到。本文主要记录原理性的内容,也会包含一些代码,具体使用请看文章。先把文章地址贴出来

AsyncDisplayKit2.0教程上 

AsyncDisplayKit2.0教程下

这篇文章中的例子可以直接运行,另外的可以自己查看 AsyncDisplaykit2.0

安装

项目使用CocoaPods安装AsynDisplayKit,在Pod文件中输入安装

source 'https://github.com/CocoaPods/Specs.git'

target "AsyncDisplayKitForMit" do

pod 'AsyncDisplayKit'

end

使用介绍

在主线程中进行的一些大量操作包括:

计算大小和布局:包括 -heightForRowAtIndexPath: 或对 UILabel 上进行 -sizeThatFits 调用,以及大量的自动布局约束的解析。

图片解码:在一个 Image View 上使用 UIImage 就意味着要进行图片数据的解码。

绘图:复杂文本以及手动绘制渐变色和阴影。

对象生命周期:创建、操作和销毁系统对象(比如创建一个 UIView)。

在正确使用的情况下,AsynDisplayKit 默认允许你以异步方式操作所有的计算大小、布局和绘图操作。不需要进行任何其它的优化,App 就能够大量减少需要在主线程上进行的工作。

ASDisplayNode 简介

ASDisplayNode 是 ASDK 的核心类,甚至可以说是“心脏”,就像 MVC 中的 view,可以看做是另一种 UIView 或 CALayer。理解一个“节点”对象的最好方法是参考 UIView 和 CALayer 的关系,你对此应该很熟悉了。

在一个 iOS App 中,屏幕上的每一个对象都表示了一个 CALayer 对象。UIView 私底下会创建和拥有一个 CALayer,通过这个 CALayer 来感知触摸或其他功能。UIView 自身并不是 CALayer 子类。相反,它包含了一个 CALayer 对象,并为它添加了一些功能。

这种概念也沿袭进了 ASDisplayNode:你可以认为它包含了一个 view,就好比 view 包含了一个 layer。

将节点通过一个普通的 View 放到表格上,最终使它们能够从后台队列中创建和配置,默认情况下,它们会被异步渲染。

幸运的是,这个 API 处理节点的方式和使用 UIView 或 CALayer 差不多。所有的 View 属性都可以在节点类上找到相同的属性。你还可访问底层的 view 或 layer——就像你可以通过 .layer 访问 UIView 的 layer 一样。

节点容器

要让节点对象尽可能地提升性,必须将它和 4 个容器类协同工作。 

这 4 个容器类分别是:

ASViewController: 一个 UIViewController 子类,允许你创建节点并进行管理。

ASCollectionNode 和 ASTableNode: 对应于 UICollectionView 和 UITableView 的 Node 子类,封装了其底层细节。

ASPagerNode: 一个 ASCollectionNode 子类,封装了扫动手势,对应于 UIKit 的 UIPageViewController。

这也太简单了,但真正的秘密其实来自于 ASRangeController,这 4 个类都会通过它来影响所包含的节点的行为。现在,请听我说,暂且将那些内容保留到后面解释。

使用

a:导入框架 #import <AsyncDisplayKit/AsyncDisplayKit.h>

b:声明tabelNode属性

@property (strong, nonatomic) ASTableNode *tableNode;

c:初始化容器,设置 TableNode 的数据和委托

和 UITableView 一样,ASTableNode 也使用了数据源和委托来获得相关信息。Table Node 的 ASTableDataSource 和 ASTableDelegate 协议和 UITableViewDataSource 和 UITableViewDelegate 协议非常类似。事实上,它们的方法定义都很像,比如 -tableNode:numberOfRowsInSection:。当然,这两套协议也不是完全没有区别,因为 ASTableNode 的行为和 UITableView 多少还是有一点不同。

 _tableNode = [[ASTableNode alloc]initWithStyle:UITableViewStylePlain];

   self.tableNode.dataSource = self;

   self.tableNode.delegate = self;

   self.tableNode.view.separatorStyle = UITableViewCellSeparatorStyleNone;

   [self.view addSubnode:self.tableNode];

d:然后,修改 -viewWillLayoutSubviews 方法:

- (void)viewWillLayoutSubviews {  

[superviewWillLayoutSubviews];

self.tableNode.frame = self.view.bounds;

}

到现在相当于创建好了tableview并设置好其frame,显示cell需要再实现其数据源方法

e:遵守数据源相关协议

@interface AnimalTableController()<ASTableDataSource,ASTableDelegate>

f:实现两个显示前重要的协议

- (NSInteger)tableNode:(ASTableNode *)tableNode numberOfRowsInSection:(NSInteger)section { //返回多少行

  return self.animals.count;

}

然后,ASTableNodes 返回 cell 的方式和 UITableView 有所不同。将 -tableView:cellForRowAtIndexPath: 方法替换为:

 (ASCellNodeBlock)tableNode:(ASTableView *)tableView nodeBlockForRowAtIndexPath:(NSIndexPath*)indexPath {

RainforestCardInfo *animal  = self.animals[indexPath.row];

ASCellNode *(^cellNodeBlock)() = ^ASCellNode *() {

        TableViewNodeCell *cellNode = [[TableViewNodeCell alloc] initWithHaiTao:haiTaoStyle];

        return cellNode;

    };

return cellNodeBlock;

}

代码解释如下:

TableViewNodeCell继承自ASCellNode,一个 ASCellNode 等同于 UITableViewCell 或 UICollectionViewCell。尤其要注意这个方法返回的是一个 ASCellNodeBlock。因为一个 ASTableNode 在内部维护了所有的 cell,为每个 cell 的 Index Path 指定了一个块,这样当需要的时候就能够异步地初始化所有 cell。 

首先,你需要获得一个数据模型对象,以便渲染这个 cell。这已经是固定的套路了。获取数据,然后将它传给后面的闭包。IndexPath 在闭包中不需要,这个例子中在闭包被调用之前数据就会先发生改变。

然后返回一个闭包,闭包中返回的类型必须是 ASCellNode。

不需要关心 cell 重用的问题,因此只需要实例化一个 cell。注意,你返回的是一个 CardNode 而不是 CardCell。

这里有一点要注意。你可能也注意到了,使用 ASDK 的时候 cell 不会进行重用。

g:相信你也知道了,在使用 UITableView 的时候通常都需要实现一个 -tableView:heightForRowAtIndexPath: 方法。这是因为 UIKit 是通过这个委托方法来计算每个 cell 的高度的。

ASTableDelegate 中没有 -tableView:heightForRowAtIndexPath: 方法。如果使用 ASDK, 所有的 ASCellNodes 都自己负责计算它们的大小。不需要提供一个固定的高度,你可以为每个 cell 指定一个最大尺寸和最小尺寸。这个例子中,你需要让每个 cell 至少占据屏幕 2/3 的高度。

现在我们暂时不讨论这个,细节会在第二部分进行讨论。 

现在,将 -tableView:heightForRowAtIndexPath: 方法替换为:

- (ASSizeRange)tableView:(ASTableView*)tableNode  constrainedSizeForRowAtIndexPath:(NSIndexPath*)indexPath { 

 CGFloat width = [UIScreen mainScreen].bounds.size.width;  

CGSizemin= CGSizeMake(width, ([UIScreen mainScreen].bounds.size.height/3) *2);  CGSizemax= CGSizeMake(width, INFINITY);

returnASSizeRangeMake(min,max);

}

//剩下的重要内容就在自定义ASCellNode中了,包括里面的控件创建与布局。

上一篇下一篇

猜你喜欢

热点阅读