Subclassing
创建子类时最重要的区别是您是编写ASDKViewController还是ASDisplayNode。这听起来很明显,但由于其中一些差异是微妙的,所以记住这一点很重要。
ASDisplayNode
虽然子类化node
类似于编写UIView子类,但要遵循一些准则,以确保充分利用框架的潜力,并确保node
的行为符合预期。
-init
使用nodeBlocks
时,在后台线程上调用此方法。但是,由于在-init
完成之前没有其他方法可以运行,因此不必在该方法中使用锁。
要记住的最重要的一点是init
方法必须能够在任何队列上被调用。最重要的是,你不应该初始化任何一个对象。node
.layer
.X
或node
.view
.X
)或在初始值设定项中添加任何手势识别器。相反,做这些事情在-didLoad
。
-didLoad
这个方法在概念上类似于UIViewController
的-viewDidLoad
方法;它只调用一次,是加载后台view
的地方。它保证在主线程上被调用,并且是执行任何UIKit
操作(例如添加手势识别器、触摸view
/层、初始化UIKit
对象)的适当位置。
-layoutSpecThatFits:
此方法定义布局并在后台线程上执行繁重的计算。此方法用于构建布局规范对象,该对象将生成node
的size
以及所有子node
的size
和position
。这是你将把你的大部分布局代码。
创建的layout spec
对象是可延展的,直到它在此方法中返回为止。在这一点之后,它将是不变的。记住不要缓存布局规范供以后使用,而是在必要时重新创建它们。
因为它是在后台线程上运行的,所以不应该设置任何node
.layer
或者node
.layer
这里的属性。另外,除非您知道自己在做什么,否则不要在此方法中创建任何node
。此外,与其他方法重写不同,不必以对super
的调用开始此方法。
-layout
在这个方法中对super
的调用是应用layoutSpec
结果的地方;在这个方法调用super
之后,layout spec
将被计算出来,所有子node
都将被测量和定位。
-layout
在概念上类似于UIViewController
的-viewWillLayoutSubviews
。这是更改隐藏属性、根据需要设置基于view
的属性(不是可布局属性)或设置背景颜色的好地方。您可以在-layoutSpecThatFits:
设置背景色,但可能存在计时问题。如果您碰巧在使用任何UIViews
,可以在这里设置它们的frame
。但是,您始终可以使用-initWithViewBlock:
创建一个node
包装器,然后在其他地方的后台线程上调整它的大小。
此方法在主线程上调用。但是,如果您使用的是布局规范,您不应该过于依赖此方法,因为最好在主线程之外进行布局。不到十分之一的子类需要这个。
layout
的一个很好的用法是用于特定的情况,在这种情况下,您希望子node
的大小与您的实际大小相同。 当你想要一个collectionNode
占据全屏时。布局规范不支持这种情况,通常最容易在这种方法中使用单行手动设置frame
:
subnode.frame = self.bounds;
如果您希望在ASDKViewController
中获得相同的效果,那么可以在-viewWillLayoutSubviews
中执行相同的操作,除非您的node
是initWithNode
中的node
,在这种情况下,它将自动执行此操作。
ASDKViewController
ASDKViewController
是一个常规的UIViewController
子类,具有管理节点的特殊功能。因为它是一个UIViewController
子类,所以所有方法都是在主线程上调用的(您应该始终在主线程上创建一个ASDKViewController
)。
-init
此方法在ASDKViewController
生命周期的最初调用一次。与UIViewController
初始化一样,最好不要访问self.view或者self.node.view
在该方法中,因为它将强制提前创建view。相反,在-viewDidLoad
中执行任何view访问。
ASDKViewController
的指定初始值设定项为initWithNode
:。典型的初始值设定项看起来像下面的代码。在调用super
之前,请注意如何创建ASDKViewController
的节点。ASDKViewController
管理节点的方式与UIViewController
管理view
的方式类似,但初始化略有不同。
- (instancetype)init
{
_pagerNode = [[ASPagerNode alloc] init];
self = [super initWithNode:_pagerNode];
// setup any instance variables or properties here
if (self) {
_pagerNode.dataSource = self;
_pagerNode.delegate = self;
}
return self;
}
-loadView
我们建议您不要使用此方法,因为它与-viewdiload
相比没有特别的优势,并且有一些缺点。但是,只要不设置self.view
属性设置为其他值。调用[super loadView]
会为你将其设置为node.view
。
-viewDidLoad
此方法在ASDKViewController
的生命周期中调用一次,即在加载view
之后立即调用。这是您应该访问节点view
的最早时间。这是一个很好的地方,可以放置任何只运行一次并且需要访问view
/layer
的设置代码,例如添加一个手势识别器。
布局代码永远不应该放在这个方法中,因为当几何图形发生变化时,它将不会被再次调用。注意,对于UIViewController
也是如此;将布局代码放在该方法中是不好的做法,即使您当前不希望几何体发生更改。
-viewWillLayoutSubviews
此方法与节点的-layout
方法在同一时间调用,并且在ASDKViewController
的生命周期中可以多次调用;每当ASDKViewController
的节点边界发生更改(包括旋转、拆分屏幕、,键盘显示)以及层次结构发生更改时(子级正在添加、删除或更改大小)。
为了保持一致性,最好将所有布局代码都放在这个方法中。因为它的调用不是很频繁,所以即使不直接依赖于大小的代码也属于这里。
-viewWillAppear: / -viewDidDisappear:
这些方法在ASDKViewController
的节点出现在屏幕上之前(该节点可见的最早时间)以及从view
层次结构中移除之后(它不再可见的最早时间)调用这些方法。这些方法提供了一个很好的机会来启动或停止与控制器的演示或解除相关的动画。这也是一个记录用户操作的好地方。
尽管这些方法可能被多次调用并且几何信息可用,但它们并不是针对所有几何图形更改而调用的,因此不应用于核心布局代码(超出特定动画所需的设置)。