Texture核心點(B)

一: 智能預(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)將在它們滾動時不斷更新恢暖。

接口狀態(tài)范圍

節(jié)點將處于以下范圍之一中:

接口狀態(tài) 描述
Preload 遠離可見的最遠距離。這是從外部來源收集內(nèi)容的地方踩身,無論是API還是本地磁盤胀茵。
Display 在這里,顯示任務(wù)挟阻,如文本光柵化和圖像解碼。
Visible 該節(jié)點在屏幕上至少有一個像素。
1.2: ASRangeTuningParameters

每個這些范圍的大小以“screenfuls”來衡量附鸽。盡管使用默認大小在很多用例中也能很好地工作脱拼,但可以通過在screenfuls為范圍類型設(shè)置調(diào)整參數(shù)來輕松調(diào)整它們。

image

在上面的可視化滾動視圖中坷备,用戶正在向下滾動熄浓。如您所見,將要滾動方向上的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包裝一個UIScrollViewASCollectionNode包裝一個UICollectionView撵溃。 liveMapMode中的ASMapNodeUIMapView的同步包裝器疚鲤。

四: 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.xnode.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.viewnode.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.viewself.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: 常見的概念誤解
5.1.3: 常見問題
  • 1: * If you care about performance, do not use CALayer's .cornerRadius property (or shadowPath, border or mask).

    CALayercornerRadius屬性的使用是災(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 LayoutInterfaceBuilder较性。值得注意的是用僧,這兩種技術(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)換所有單元其徙。在這里閱讀更多

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末喷户,一起剝皮案震驚了整個濱河市唾那,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌褪尝,老刑警劉巖闹获,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異河哑,居然都是意外死亡避诽,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門璃谨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沙庐,“玉大人,你說我怎么就攤上這事睬罗」旃Γ” “怎么了?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵容达,是天一觀的道長。 經(jīng)常有香客問我垂券,道長花盐,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任菇爪,我火速辦了婚禮算芯,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凳宙。我一直安慰自己熙揍,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布氏涩。 她就那樣靜靜地躺著届囚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪是尖。 梳的紋絲不亂的頭發(fā)上意系,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音饺汹,去河邊找鬼蛔添。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的迎瞧。 我是一名探鬼主播夸溶,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼凶硅!你這毒婦竟也來了缝裁?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤咏尝,失蹤者是張志新(化名)和其女友劉穎压语,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體编检,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡胎食,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了允懂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片厕怜。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蕾总,靈堂內(nèi)的尸體忽然破棺而出粥航,到底是詐尸還是另有隱情,我是刑警寧澤生百,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布递雀,位于F島的核電站,受9級特大地震影響蚀浆,放射性物質(zhì)發(fā)生泄漏缀程。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一市俊、第九天 我趴在偏房一處隱蔽的房頂上張望杨凑。 院中可真熱鬧,春花似錦摆昧、人聲如沸撩满。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伺帘。三九已至,卻和暖如春勇吊,著一層夾襖步出監(jiān)牢的瞬間曼追,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工汉规, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留礼殊,地道東北人驹吮。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像晶伦,于是被迫代替她去往敵國和親碟狞。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容