这是 Texture 文档系列翻译,其中结合了自己的理解和工作中的使用体会。如果哪里有误,希望指出。
Texture 使用 ARC(Automatic Reference Counting)管理内存。因此,一旦对象不被强引用,会尽快将其释放。当涉及到ASDisplayNode
及其子类时,不同种类的 node 具有不同的生命周期。了解其生命周期、加载状态、何时进入页面有助于深入了解 Texture。
被 node container 管理的 node
Node container 管理其管理 node 的生命周期。通常,node container 根据需要尽快为 node 分配内存,并在不需要时释放他们。Texture 假定 node container 独自管理其 node,并且希望开发者不要引用或修改 node 的生命周期。例如,开发者不应保存ASCollectionNode
、ASTableNode
、ASPagerNode
创建的ASCellNode
,也不要复用ASCellNode
。
一旦将ASCellNode
添加到ASCollectionNode
或ASTableNode
,就会为其ASCellNode
分配内存。例如,刷新数据、插入数据。UICollectionView
和UITableView
会对 cell 进行复用,但ASCollectionNode
和ASTableNode
不会对 cell 进行复用,因此ASCellNode
数量和ASCollectionNode
、ASTableNode
当前 row/item 数一致。
目前,ASCollectionNode
和ASTableNode
插入数据时会立即分配内存。如果批量拉取了100条数据,就会在 batch update 时分配100个 cell node。也会计算每个 cell 的布局。最终,node container 会管理100个或更多 cell,并立即计算出每个 cell 的布局。
Node container 处理大量 cell 时,需要一定时间来处理上述操作。因此推荐使用 node block,以便 cell node 可以在后台线程并发创建,而非在主线程顺序创建。如果想要进一步提升性能,可以使用 batch fetching API 预拉取数据。
可以在ASDataController
查看实现细节,ASDataController
是唯一在任一时间均对所有 cell 进行强引用的类。
ASCollectionLayout
为了解决一次分配太多 cell 的问题,为ASCollectionNode
增加了新 API,以便在用户滑动时初始化 cell、计算布局。但由于某些限制,该功能只能用于已知 cell 大小的布局。例如,相册、电子书等。
具体可以查看ASCollectionLayout
、ASCollectionGalleryLayoutDelegate
和ASCollectionFlowLayoutDelegate
。
释放 ASCellNode
由于ASCellNode
不会进行复用,其生命周期会比UICollectionViewCell
、UITableViewCell
长。当ASCellNode
不再使用,并从 container node 移除后会被释放。例如,下拉刷新、删除 cell,或 container node 被移除。
Container node 被移除后,其 cell node 并不会立即释放。这是因为 table node 和 collection node 可能持有大量 cell node,同时释放会造成明显卡顿。为避免这一问题,ASCollectionNode
和ASTableNode
释放其对象时(特别是ASDataController
),借助ASDeallocQueue
类在后台线程进行释放。由于ASDataController
强引用了所有 cell node,所有 cell node 也会在后台线程释放。使用 Instruments 分析内存泄漏时,需要注意 cell node 延迟释放这一问题。
ASDeallocQueue
ASDeallocQueue
强引用所持有对象,以便延迟释放,最后在后台线程进行释放。
未被 node container 管理的 node
将 node 添加到父视图后,直到从父视图移除或父视图释放才会释放 node。如果未从父视图移除,则 node 生命周期将于父视图一致。由于 node 一般长时间存在于视图层级中,整个 node 生命周期与 root node 一致。
ASM 管理下的 node 生命周期
ASM 通过布局规范决定视图层级,Texture 通过当前布局规范、过去布局规范计算 node 的插入、移除。为了支持插入、移除动画,新 node 在动画开始时添加,原来 node 在视图结束时移除。