Common Developer Mistakes
- Do not access a node's view in
- Make sure you access your data source outside of a
- Take steps to avoid a retain cycle in
Common Conceptual Misunderstandings
ASCellNodesare not reusable.
- Layout Specs are regenerated each time layout is called.
- The difference between all of the sizes used in our powerful Layout API.
- If you care about performance, do not use
.cornerRadiusproperty (or shadowPath, border or mask).
- Texture does not support UIKit Auto Layout.
- Can I use my
ASDisplayNodekeep alive reference.
Accessing the node’s view before it is loaded
-init methods are often called off the main thread, therefore it is imperative that no UIKit objects are accessed. Examples of common errors include accessing the node’s view or creating a gesture recognizer. Instead, these operations are ideal to perform in
Interacting with UIKit in
-init can cause crashes and performance problems.
Make sure you access your data source outside the node block
indexPath parameter is only valid outside the node block returned in
nodeBlockForRowAtIndexPath:. Because these blocks are executed on a background thread, the
indexPath may be invalid by execution time, due to additional changes in the data source.
See an example of how to correctly code a node block in the ASTableNode page. Just as with UIKit, it will cause an exception if Nil is returned from the block for any
Take steps to avoid a retain cycle in viewBlocks
initWithViewBlock: it is important to prevent a retain cycle by capturing a strong reference to self. The two ways that a cycle can be created are by using any instance variable inside the block or directly referencing self without using a weak pointer.
You can use properties instead of instance variables as long as they are accessed on a weak pointer to self.
Because viewBlocks are always executed on the main thread, it is safe to preform UIKit operations (including gesture recognizer creation and addition).
Although the block is destroyed after the view is created, in the event that the block is never run and the view is never created, then a cycle can persist preventing memory from being released.
Texture does not use cell reuse, for a number of specific reasons, one side effect of this is that it eliminates the large class of bugs associated with cell reuse.
LayoutSpecs Are Regenerated
A node’s layoutSpec gets regenerated every time its
layoutThatFits: method is called.
Layout API Sizing
If you’re confused by
ASSizeRange, check out our Layout API Sizing guide.
CALayer’s .cornerRadius Property Kills Performance
CALayer’s’ .cornerRadius property is a disastrously expensive property that should only be used when there is no alternative. It is one of the least efficient, most render-intensive properties on CALayer (alongside shadowPath, masking, borders, etc). These properties trigger offscreen rendering to perform the clipping operation on every frame — 60FPS during scrolling! — even if the content in that area isn’t changing.
.cornerRadius will visually degraded performance on iPhone 4, 4S, and 5 / 5C (along with comparable iPads / iPods) and reduce head room and make frame drops more likely on 5S and newer devices.
For a longer discussion and easy alternative corner rounding solutions, please read our comprehensive corner rounding guide.
Texture does not support UIKit Auto Layout or InterfaceBuilder
UIKit Auto Layout and InterfaceBuilder are not supported by Texture. It is worth noting that both of these technologies are not permitted in established and disciplined iOS development teams, such as at Facebook, Instagram, and Pinterest.
However, Texture’s Layout API provides a variety of ASLayoutSpec objects that allow implementing automatic layout which is more efficient (multithreaded, off the main thread), easier to debug (can step into the code and see where all values come from, as it is open source), and reusable (you can build composable layouts that can be shared with different parts of the UI).
ASDisplayNode keep alive reference
ASTextNode *title=[[ASTextNode alloc]init]; title.attributedString=Text; [self addSubnode:title]; retain cycles ( "-> _keepalive_node -> ASTextNode ", "-> _view -> _ASDisplayView " )
This retain cycle is intentionally created because the node is in a “live” view hierarchy (it is inside the UIWindow that is onscreen).
To see why this is necessary, consider that Apple also creates this retain cycle between UIView and CALayer. If you create a UIView and add its layer to a super layer, and then release the UIView, it will stay alive even though the CALayer delegate pointing to it is weak.
For the same reason, if the node’s view is a descendant of a window, but there is no reference to the node, we keep the node alive with a strong reference from the view.
Good application design should not rely on this behavior, because a strong reference to the node should be maintained by the subnodes array or by an instance variable. However, this condition occasionally occurs, for example when using a UIView animation API. This cycle should never create a leak or even extend the lifecycle of a node any longer than it is absolutely necessary.
Texture supports using
UICollectionViewCells alongside native
Note that these UIKit cells will not have the performance benefits of
ASCellNodes (like preloading, async layout, and async drawing), even when mixed within the same
However, this interoperability allows developers the flexibility to test out the framework without needing to convert all of their cells at once. Read more here.