一: 智能預(yù)加載
二: Node Containers
三: Node Subclasses
四: Subclassing
五: FAQ
一: 智能預(yù)加載
雖然Texture的異步渲染和異步測量的能非常強大,但對于Texture還有一個非常重要特點是智能預(yù)加載。
正如“入門指南”中指出的那樣寡润,在節(jié)點容器的上下文之外使用節(jié)點將體現(xiàn)不出Texture的優(yōu)勢。這是因為只有接點容器才可以獲取所有節(jié)點當前接口狀態(tài)蚜印。
此接口狀態(tài)屬性由ASRangeController
根據(jù)節(jié)點的狀態(tài)不斷更新担猛,節(jié)點容器管理節(jié)點的創(chuàng)建和維護
在容器外部使用的節(jié)點不能正常使用和更新其狀態(tài)松蒜。這有時會導(dǎo)致閃爍擂涛,這種情況是沒有警告??
1.1: Interface State Ranges
當節(jié)點添加到滾動或分頁界面時读串,它們通常位于以下幾種狀態(tài)中的一種。隨著滾動視圖的滾動撒妈,它們的接口狀態(tài)將在它們滾動時不斷更新恢暖。
節(jié)點將處于以下范圍之一中:
接口狀態(tài) | 描述 |
---|---|
Preload | 遠離可見的最遠距離。這是從外部來源收集內(nèi)容的地方踩身,無論是API還是本地磁盤胀茵。 |
Display | 在這里,顯示任務(wù)挟阻,如文本光柵化和圖像解碼。 |
Visible | 該節(jié)點在屏幕上至少有一個像素。 |
1.2: ASRangeTuningParameters
每個這些范圍的大小以“screenfuls”來衡量附鸽。盡管使用默認大小在很多用例中也能很好地工作脱拼,但可以通過在screenfuls
為范圍類型設(shè)置調(diào)整參數(shù)來輕松調(diào)整它們。
在上面的可視化滾動視圖中坷备,用戶正在向下滾動熄浓。如您所見,將要滾動方向上的screenfuls
大小比用戶遠離的拖尾方向大得多省撑。 如果用戶要改變方向赌蔑,則前進和拖尾狀態(tài)將動態(tài)交換以保持內(nèi)存使用最佳。 這使您可以擔(dān)心定義前導(dǎo)和尾隨尺寸竟秫,而無需擔(dān)心對用戶變化的滾動方向作出反應(yīng)娃惯。
智能預(yù)加載還可以在多個維度上運行
1.3: 接口狀態(tài)的回調(diào)
當用戶滾動時,節(jié)點在范圍內(nèi)移動并做出適當反應(yīng)肥败。您自己的節(jié)點子類可以通過實現(xiàn)相應(yīng)的回調(diào)方法來輕松利用此機制趾浅。
-
1: Visible Range
-didEnterVisibleState
-didExitVisibleState
-
2: Display Range
-didEnterDisplayState
-didExitDisplayState
-
3: Preload Range
-didEnterPreloadState
-didExitPreloadState
二: 節(jié)點容器
2.1: Use Nodes in Node Containers(在節(jié)點容器中使用節(jié)點)
強烈建議您在節(jié)點容器中使用Texture的節(jié)點。 Texture提供以下節(jié)點容器馒稍。
Texture節(jié)點容器 | UIKit等效 |
---|---|
ASCollectionNode | UICollectionView |
ASPagerNode | UIPageViewController |
ASTableNode | UITableView |
ASViewController | UIViewController |
ASNavigationController | UINavigationController 實現(xiàn)ASVisibility 協(xié)議皿哨。 |
ASTabBarController | UITabBarController 實現(xiàn)ASVisibility 協(xié)議。 |
示例代碼和特定示例項目在每個節(jié)點容器的文檔中突出顯示纽谒。
2.2: 我通過使用節(jié)點容器獲得什么证膨?
節(jié)點容器自動管理其節(jié)點的智能預(yù)加載。這意味著所有節(jié)點的布局測量鼓黔,數(shù)據(jù)讀取央勒,解碼和渲染都將以異步方式完成。 除其他便利之外请祖,這就是為什么建議節(jié)點要保證在容器節(jié)點內(nèi)使用的原因订歪。
請注意,雖然可以直接使用節(jié)點(沒有Texture節(jié)點容器)肆捕,但除非添加其他調(diào)用刷晋,否則只有在屏幕上顯示時才會開始顯示(如UIKit所做的那樣)。 這可能導(dǎo)致性能下降和內(nèi)容閃爍體現(xiàn)不出Texture的優(yōu)勢
三: Node Subclasses
Texture提供以下節(jié)點慎陵。
與UIKit組件相比眼虱,使用節(jié)點的一個核心優(yōu)勢是 所有節(jié)點都可以不在主線程進行布局和顯示,因此主線程可以及時響應(yīng)用戶交互事件席纽。
Texture Node | UIKit Equivalent |
---|---|
ASDisplayNode | 替代UIView Texture節(jié)點的基類 |
ASCellNode | 替代UITableViewCell & UICollectionViewCell ASCellNode用于ASTableNode捏悬,ASCollectionNode和ASPagerNode
|
ASScrollNode | 替代UIScrollView 此節(jié)點對于創(chuàng)建包含其他節(jié)點的自定義可滾動區(qū)域很有用 |
ASEditableTextNode | 替代UITextView
|
ASTextNode | 替代UILabel
|
ASImageNode | 替代UIImageView
|
ASNetworkImageNode | |
ASMultiplexImageNode | |
ASVideoNode | 替代AVPlayerLayer
|
ASVideoPlayerNode | 替代UIMoviePlayer
|
ASControlNode | 替代UIControl
|
ASButtonNode | 替代UIButton
|
ASMapNode | 替代MKMapView
|
盡管與UIKit組件大致相當,但一般而言润梯,Texture節(jié)點提供更高級的功能和便利过牙。 例如甥厦,ASNetworkImageNode
會自動加載和緩存管理,支持漸進式j(luò)peg和動畫gif寇钉。
AsyncDisplayKitOverview示例應(yīng)用程序給出了上面列出的每個節(jié)點的基本實現(xiàn)刀疙。
三: Node Inheritance Hierarchy(節(jié)點繼承層次結(jié)構(gòu))
所有texture節(jié)點都從ASDisplayNode繼承。
[圖片上傳失敗...(image-a3290d-1569489726113)]
以藍色突出顯示的節(jié)點是UIKit元素的同步包裝扫倡。例如谦秧,ASScrollNode
包裝一個UIScrollView
,ASCollectionNode
包裝一個UICollectionView
撵溃。 liveMapMode中的ASMapNode
是UIMapView
的同步包裝器疚鲤。
四: Subclassing(子類)
創(chuàng)建子類時最重要的區(qū)別在于您是 ASViewController
還是ASDisplayNode
的子類。這聽起來很明顯缘挑,但由于其中的一些差異很微妙集歇,注意當前的子類
4.1: ASDisplayNode
雖然子類化節(jié)點類似于編寫UIView子類,但還是有一些原則需要遵循卖哎,以確保您充分利用該框架的能力鬼悠。
1:
init
使用nodeBlocks
子線程
2: didLoad 主線程
3: layoutSpecThatFits 子線程
4: layout 主線程
-init
init
使用nodeBlocks
構(gòu)建方法是在后臺線程上調(diào)用此方法。但是亏娜,因為在-init
完成之前沒有其他方法可以運行焕窝,所以在此方法中沒有必要使用鎖。
最重要的事情是你的init
方法必須能夠在任何隊列上被調(diào)用维贺。 最值得注意的是它掂,這意味著您不應(yīng)該初始化任何UIKit
對象, 觸摸節(jié)點的視圖或圖層(例如node.layer.x
或node.view.x
),或者在初始化程序中添加任何手勢識別器溯泣。 相反虐秋,在-dldLoad
中執(zhí)行這些操作。
-didLoad
這個方法在概念上類似于UIViewController
的-viewDidLoad
方法; 它被調(diào)用一次垃沦,并且是加載背景視圖之后客给。 didLoad
在主線程中調(diào)用,并且是執(zhí)行任何UIKit事物(例如添加手勢識別器肢簿,觸摸視圖/圖層靶剑,初始化UIKit對象)的適當位置。
-layoutSpecThatFits:
該方法定義了布局在后臺線程上執(zhí)行繁重的計算池充。此方法用于構(gòu)建將節(jié)點大小的布局規(guī)范對象桩引,以及所有子節(jié)點的大小和位置。 這是您將放置大部分布局代碼的地方收夸。
您創(chuàng)建的布局規(guī)范對象具有延展性坑匠,直到它在此方法中返回為止。 在這之后卧惜,它將是不可變的厘灼。 記住不要緩存布局規(guī)格供以后使用夹纫,而是在必要時重新創(chuàng)建它們。
由于它在后臺線程上運行手幢,因此不應(yīng)在此處設(shè)置任何node.view
或node.layer
屬性捷凄。另外忱详,除非您知道自己在做什么围来,否則不要在此方法中創(chuàng)建任何節(jié)點。此外匈睁,與其他方法覆蓋不同监透,調(diào)用super
的方法并不是必需的。
-layout
在這種方法中super
調(diào)用是layoutSpec
的結(jié)果應(yīng)用的地方;在此方法調(diào)用super之
后航唆,布局規(guī)格將被計算并且所有子節(jié)點將被測量和定位胀蛮。
-layout
在概念上與UIViewController
的-viewWillLayoutSubviews
類似。 這是更改隱藏屬性的好地方糯钙,如果需要(不可布局的屬性)設(shè)置基于視圖的屬性或設(shè)置背景顏色粪狼。 您可以將背景顏色設(shè)置放在-layoutSpecThatFits:
中,但可能存在時間問題任岸。 如果你碰巧使用任何UIViews再榄,你可以在這里設(shè)置它們的框架。 但是享潜,您始終可以使用-initWithViewBlock
創(chuàng)建節(jié)點包裝:然后在其他位置的后臺線程上調(diào)整大小困鸥。
這個方法在主線程中調(diào)用。但是剑按,如果您使用布局規(guī)范疾就,則不應(yīng)過多依賴此方法,因為最好從主線程中剔除布局艺蝴。 10個小類中不到1個還可以接受猬腰。
-layout
的一個很好的用途是針對特定情況,在這種情況下猜敢,您希望子節(jié)點是您的確切大小姑荷。例如。當你想要一個collectionNode
占據(jù)整個屏幕锣枝。布局規(guī)范不支持這種情況厢拭,并且在此方法中使用單行手動設(shè)置框架通常最簡單:
subnode.frame = self.bounds;
如果你希望在ASViewController
中有同樣的效果,你可以在-viewWillLayoutSubviews
中做同樣的事情撇叁,除非你的節(jié)點是initWithNode
中的節(jié)點:在這種情況下供鸠,它會自動完成。
4.2: ASViewController
ASViewController
是一個常規(guī)的UIViewController
子類陨闹,它具有管理節(jié)點的特殊功能楞捂。 由于它是一個UIViewController
子類薄坏,因此所有UIViewController
方法都在主線程上調(diào)用(并且您應(yīng)該始終在主線程上創(chuàng)建一個ASViewController
)。
4.2.1:-init
該方法在ASViewController
生命周期的最初階段被調(diào)用一次寨闹。 和UIViewController
初始化一樣胶坠,最好的做法是不要在這個方法中訪問self.view
或self.node.view
。 相反繁堡,在-viewDidLoad
中執(zhí)行任何視圖訪問沈善。
ASViewController
的指定初始化程序是initWithNode :
一個典型的初始化程序看起來像下面的代碼。請注意在調(diào)用super
之前如何創(chuàng)建ASViewController
的節(jié)點椭蹄。 ASViewController
類似于UIViewController
管理視圖來管理節(jié)點闻牡,但初始化稍有不同。
OC
- (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;
}
swift
init() {
let pagerNode = ASPagerNode()
super.init(node: pagerNode)
pagerNode.setDataSource(self)
pagerNode.setDelegate(self)
}
4.2.2:-loadView(不推薦使用)
我們建議您不要使用這種方法绳矩,因為它與-viewDidLoad相比沒有什么特別的優(yōu)勢罩润,并且有一些缺點。 但是翼馆,只要不將self.view屬性設(shè)置為不同的值割以,就可以安全使用。 對[super loadView]的調(diào)用會將其設(shè)置為node.view应媚。
4.2.3: -viewDidLoad
這個方法在ASViewController
的生命周期中被調(diào)用一次严沥,緊接在-loadView
之后。 這是您訪問節(jié)點視圖的最早時間珍特。 這是放置任何設(shè)置代碼的好地方祝峻,它只能運行一次,并需要訪問視圖/圖層扎筒,例如添加手勢識別器莱找。
布局代碼不應(yīng)該放在這個方法中,因為當UI變化時它不會再被調(diào)用嗜桌。 注意這對UIViewController同樣適用;即使您目前不期望幾何變化奥溺,在此方法中放置布局代碼也是不好的做法。
4.2.4 -viewWillLayoutSubviews
該方法在與節(jié)點的-layout
方法完全相同的時間被調(diào)用骨宠,并且可以在ASViewController
的生命周期中多次調(diào)用該方法; 只要ASViewController
節(jié)點的邊界發(fā)生變化(包括旋轉(zhuǎn)浮定,分割屏幕,鍵盤顯示)以及層次結(jié)構(gòu)發(fā)生變化(兒童被添加层亿,刪除或更改大需胱洹),就會調(diào)用它匿又。
為了一致性方灾,最好的做法是將所有布局代碼放入此方法中。因為它不是非常頻繁地調(diào)用,甚至不直接依賴于大小的代碼也屬于這里裕偿。
4.2.5 -viewWillAppear: / -viewDidDisappear:
這些方法在ASViewController
的節(jié)點出現(xiàn)在屏幕上(最早可見時)以及從視圖層次結(jié)構(gòu)(最早不再可見的時間)之后立即調(diào)用洞慎。 這些方法提供了一個很好的機會來啟動或停止與呈現(xiàn)或解除控制器相關(guān)的動畫。 這也是一個記錄用戶操作的好地方嘿棘。
盡管這些方法可能被多次調(diào)用劲腿,并且?guī)缀涡畔⒖捎茫鼈儾粫徽{(diào)用用于所有幾何變化鸟妙,因此不應(yīng)該用于核心布局代碼(超出特定動畫所需的設(shè)置)焦人。
五: FAQ
5.1 問題
5.1.1: 常見的開發(fā)人員錯誤
-
1: * Do not access a node's view in
-init:
.
節(jié)點-init
方法通常在子線程中調(diào)用,因此務(wù)必不可以訪問UIKit對象圆仔,常見錯誤包括訪問節(jié)點的視圖或創(chuàng)建手勢, 但是垃瞧,這些操作非常適合在-didLoad
中執(zhí)行在
-init
中與UIKit
交互可能會導(dǎo)致崩潰和性能問題。 -
2: * Make sure you access your data source outside of a
nodeBlock
.indexPath
參數(shù)僅在nodeBlockForItemAtIndexPath:
或nodeBlockForRowAtIndexPath:
中返回的節(jié)點塊之外有效坪郭。由于這些塊是在后臺線程上執(zhí)行的,因此脉幢,由于數(shù)據(jù)源中的其他更改歪沃,indexPath
可能因執(zhí)行時間而無效。請參閱ASTableNode頁面中如何正確編碼節(jié)點塊的示例嫌松。與UIKit一樣沪曙,如果從任何ASCellNode的塊返回Nil,它將導(dǎo)致異常萎羔。
-
3: * Take steps to avoid a retain cycle in
viewBlocks
.使用
initWithViewBlock
時:通過捕獲對self
的強引用來防止保留周期非常重要.可以創(chuàng)建循環(huán)的兩種方法是使用塊內(nèi)的任何實例變量或直接引用self而不使用弱指針只要在指向self的弱指針上訪問它們液走,就可以使用屬性而不是實例變量。
由于
viewBlocks
總是在主線程上執(zhí)行贾陷,因此可以安全地執(zhí)行UIKit
操作(包括創(chuàng)建和添加手勢識別器)缘眶。雖然在創(chuàng)建視圖后塊被銷毀,但是如果塊永遠不會運行并且從未創(chuàng)建視圖髓废,則可以保持循環(huán)以防止釋放內(nèi)存巷懈。
5.1.2: 常見的概念誤解
-
1: *
ASCellNodes
are not reusable.Texture
不使用cell重用,由于許多特定原因慌洪,這樣做的一個副作用是它消除了與單元重用相關(guān)的大量錯誤顶燕。 -
2: * Layout Specs are regenerated each time layout is called.
每次調(diào)用
layoutThatFits
方法時,節(jié)點的layoutSpec
都會重新生成冈爹。 -
3: * The difference between all of the sizes used in our powerful Layout API.
如果您對
ASRelativeDimension
涌攻,ASRelativeSize
,ASRelativeSizeRange
和ASSizeRange
感到困惑频伤,請查看我們的Layout API Sizing guide
5.1.3: 常見問題
-
CALayer
的cornerRadius
屬性的使用是災(zāi)難性恳谎,只有在沒有其他選擇的情況下才能使用。它是CALayer
上效率最低剂买,渲染最密集的屬性之一(與shadowPath惠爽,masking癌蓖,border等). 這些屬性觸發(fā)離屏渲染,以對每個幀執(zhí)行剪切操作. 滾動時60FPS婚肆! - 即使該區(qū)域的內(nèi)容沒有變化使用
cornerRadius
會在視覺上降低iPhone 4,4S和5 / 5C
(以及類似的iPad / iPod
)的性能租副,并減少頭部空間并使5S和更新設(shè)備上的幀丟失更有可能如需更長時間的討論和簡單的替代轉(zhuǎn)角解決方案,請閱讀 corner rounding guide
-
2: * Texture does not support UIKit Auto Layout.
Texture
不支持UIKit Auto Layout
和InterfaceBuilder
较性。值得注意的是用僧,這兩種技術(shù)都不允許在已建立和訓(xùn)練有素的iOS開發(fā)團隊中使用,例如Facebook赞咙,Instagram和Pinterest
但是责循,Texture的Layout API提供了各種ASLayoutSpec對象,允許實現(xiàn)更高效的自動布局(多線程攀操,脫離主線程)院仿,更容易調(diào)試(可以進入代碼并查看所有值來自哪里,因為它是開放的源)和可重用(您可以構(gòu)建可以與UI的不同部分共享的可組合布局)速和。
-
3: * Can I use my
UICollectionViewCells
with Texture?.ASTextNode *title=[[ASTextNode alloc]init]; title.attributedString=Text; [self addSubnode:title]; retain cycles ( "-> _keepalive_node -> ASTextNode ", "-> _view -> _ASDisplayView " )
由于節(jié)點處于“實時”視圖層次結(jié)構(gòu)中(位于屏幕上的UIWindow內(nèi)部)歹垫,因此有意創(chuàng)建此保留周期。
要了解為什么這樣做是必要的颠放,請考慮Apple還創(chuàng)建了UIView和CALayer之間的保留周期排惨。如果創(chuàng)建UIView并將其層添加到超級層,然后釋放UIView碰凶,即使指向它的CALayer委托很弱暮芭,它也將保持活動狀態(tài)。
出于同樣的原因欲低,如果節(jié)點的視圖是窗口的后代辕宏,但沒有對該節(jié)點的引用,則可以使用該視圖中的強引用來使該節(jié)點保持活動狀態(tài)伸头。
好的應(yīng)用程序設(shè)計不應(yīng)依賴于此行為匾效,因為對子節(jié)點的強引用應(yīng)由子節(jié)點數(shù)組或?qū)嵗兞烤S護。但是恤磷,這種情況有時會發(fā)生面哼,例如在使用UIView動畫API時。此循環(huán)絕不應(yīng)超過絕對必要的時間扫步,甚至不會延長節(jié)點的生命周期魔策。
-
4: *
ASDisplayNode
keep alive reference.Texture
支持使用ASCellNodes
來替換UICollectionViewCells
請注意,這些UIKit單元不具備
ASCellNodes
的性能優(yōu)勢, (如預(yù)加載河胎,異步布局和異步繪圖)闯袒,即使在同一ASCollectionNode
中混合使用。但是,這種互操作性允許開發(fā)人員靈活地測試框架政敢,而無需一次性轉(zhuǎn)換所有單元其徙。在這里閱讀更多。