mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-19 12:49:02 +00:00
Initial commit to cleanup modifying subnode hierarchy (#2535)
This commit is contained in:
parent
076d22e9f1
commit
dae374d482
@ -1641,8 +1641,7 @@ static inline CATransform3D _calculateTransformFromReferenceToTarget(ASDisplayNo
|
||||
|
||||
#pragma mark - Managing the Node Hierarchy
|
||||
|
||||
static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASDisplayNode *to)
|
||||
{
|
||||
ASDISPLAYNODE_INLINE bool shouldDisableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASDisplayNode *to) {
|
||||
if (!from || !to) return NO;
|
||||
if (from->_flags.synchronous) return NO;
|
||||
if (to->_flags.synchronous) return NO;
|
||||
@ -1650,6 +1649,114 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
|
||||
return YES;
|
||||
}
|
||||
|
||||
/// Returns incremented value of i if i is not NSNotFound
|
||||
ASDISPLAYNODE_INLINE NSInteger incrementIfFound(NSInteger i) {
|
||||
return i == NSNotFound ? NSNotFound : i + 1;
|
||||
}
|
||||
|
||||
/// Returns if a node is a member of a rasterized tree
|
||||
ASDISPLAYNODE_INLINE BOOL canUseViewAPI(ASDisplayNode *node, ASDisplayNode *subnode) {
|
||||
return (subnode.isLayerBacked == NO && node.isLayerBacked == NO);
|
||||
}
|
||||
|
||||
/// Returns if node is a member of a rasterized tree
|
||||
ASDISPLAYNODE_INLINE BOOL nodeIsInRasterizedTree(ASDisplayNode *node) {
|
||||
return (node->_flags.shouldRasterizeDescendants || (node->_hierarchyState & ASHierarchyStateRasterized));
|
||||
}
|
||||
|
||||
/*
|
||||
* Central private helper method that should eventually be called if submethods add, insert or replace subnodes
|
||||
* You must hold __instanceLock__ to call this.
|
||||
*
|
||||
* @param subnode The subnode to insert
|
||||
* @param subnodeIndex The index in _subnodes to insert it
|
||||
* @param viewSublayerIndex The index in layer.sublayers (not view.subviews) at which to insert the view (use if we can use the view API) otherwise pass NSNotFound
|
||||
* @param sublayerIndex The index in layer.sublayers at which to insert the layer (use if either parent or subnode is layer-backed) otherwise pass NSNotFound
|
||||
* @param oldSubnode Remove this subnode before inserting; ok to be nil if no removal is desired
|
||||
*/
|
||||
- (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnodeIndex sublayerIndex:(NSInteger)sublayerIndex andRemoveSubnode:(ASDisplayNode *)oldSubnode
|
||||
{
|
||||
if (subnode == nil || subnode == self) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a nil subnode or self as subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
if (subnodeIndex == NSNotFound) {
|
||||
ASDisplayNodeFailAssert(@"Try to insert node on an index that was not found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (subnodeIndex > _subnodes.count || subnodeIndex < 0) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a subnode at index %zd. Count is %zd", subnodeIndex, _subnodes.count);
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable appearance methods during move between supernodes, but make sure we restore their state after we do our thing
|
||||
ASDisplayNode *oldParent = subnode.supernode;
|
||||
BOOL disableNotifications = shouldDisableNotificationsForMovingBetweenParents(oldParent, self);
|
||||
if (disableNotifications) {
|
||||
[subnode __incrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
|
||||
[subnode _removeFromSupernode];
|
||||
[oldSubnode _removeFromSupernode];
|
||||
|
||||
if (_subnodes == nil) {
|
||||
_subnodes = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
ASDisplayNodeLogEvent(self, @"%@: %@", NSStringFromSelector(_cmd), subnode);
|
||||
|
||||
[_subnodes insertObject:subnode atIndex:subnodeIndex];
|
||||
|
||||
// This call will apply our .hierarchyState to the new subnode.
|
||||
// If we are a managed hierarchy, as in ASCellNode trees, it will also apply our .interfaceState.
|
||||
[subnode __setSupernode:self];
|
||||
|
||||
// Don't bother inserting the view/layer if in a rasterized subtree, because there are no layers in the hierarchy and
|
||||
// none of this could possibly work.
|
||||
if (nodeIsInRasterizedTree(self) == NO && self.nodeLoaded) {
|
||||
// If node is loaded insert the subnode otherwise wait until the node get's loaded
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[self _insertSubnodeSubviewOrSublayer:subnode atIndex:sublayerIndex];
|
||||
});
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(disableNotifications == shouldDisableNotificationsForMovingBetweenParents(oldParent, self), @"Invariant violated");
|
||||
if (disableNotifications) {
|
||||
[subnode __decrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Inserts the view or layer of the given node at the given index
|
||||
* You must hold __instanceLock__ to call this.
|
||||
*
|
||||
* @param subnode The subnode to insert
|
||||
* @param idx The index in _view.subviews or _layer.sublayers at which to insert the subnode.view or
|
||||
* subnode.layer of the subnode
|
||||
*/
|
||||
- (void)_insertSubnodeSubviewOrSublayer:(ASDisplayNode *)subnode atIndex:(NSInteger)idx
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(self.nodeLoaded, @"_insertSubnodeSubviewOrSublayer:atIndex: should never be called before our own view is created");
|
||||
|
||||
ASDisplayNodeAssert(idx != NSNotFound, @"Try to insert node on an index that was not found");
|
||||
if (idx == NSNotFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If we can use view API, do. Due to an apple bug, -insertSubview:atIndex: actually wants a LAYER index, which we pass in
|
||||
if (canUseViewAPI(self, subnode)) {
|
||||
[_view insertSubview:subnode.view atIndex:idx];
|
||||
} else {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
[_layer insertSublayer:subnode.layer atIndex:idx];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addSubnode:(ASDisplayNode *)subnode
|
||||
{
|
||||
// TODO: 2.0 Conversion: Reenable and fix within product code
|
||||
@ -1663,108 +1770,29 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
ASDisplayNodeAssert(subnode, @"Cannot insert a nil subnode");
|
||||
|
||||
// Don't add subnode if it's already if it's already a subnodes
|
||||
ASDisplayNode *oldParent = subnode.supernode;
|
||||
if (!subnode || subnode == self || oldParent == self) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Disable appearance methods during move between supernodes, but make sure we restore their state after we do our thing
|
||||
BOOL isMovingEquivalentParents = disableNotificationsForMovingBetweenParents(oldParent, self);
|
||||
if (isMovingEquivalentParents) {
|
||||
[subnode __incrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
[subnode _removeFromSupernode];
|
||||
|
||||
if (!_subnodes) {
|
||||
_subnodes = [[NSMutableArray alloc] init];
|
||||
[self _insertSubnode:subnode atSubnodeIndex:_subnodes.count sublayerIndex:_layer.sublayers.count andRemoveSubnode:nil];
|
||||
}
|
||||
|
||||
ASDisplayNodeLogEvent(self, @"%@ %@", NSStringFromSelector(_cmd), subnode);
|
||||
[_subnodes addObject:subnode];
|
||||
|
||||
// This call will apply our .hierarchyState to the new subnode.
|
||||
// If we are a managed hierarchy, as in ASCellNode trees, it will also apply our .interfaceState.
|
||||
[subnode __setSupernode:self];
|
||||
|
||||
if (self.nodeLoaded) {
|
||||
// If this node has a view or layer, force the subnode to also create its view or layer and add it to the hierarchy here.
|
||||
// Otherwise there is no way for the subnode's view or layer to enter the hierarchy, except recursing down all
|
||||
// subnodes on the main thread after the node tree has been created but before the first display (which
|
||||
// could introduce performance problems).
|
||||
ASPerformBlockOnMainThread(^{
|
||||
[self _addSubnodeSubviewOrSublayer:subnode];
|
||||
});
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(isMovingEquivalentParents == disableNotificationsForMovingBetweenParents(oldParent, self), @"Invariant violated");
|
||||
if (isMovingEquivalentParents) {
|
||||
[subnode __decrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Private helper function.
|
||||
You must hold __instanceLock__ to call this.
|
||||
|
||||
@param subnode The subnode to insert
|
||||
@param subnodeIndex The index in _subnodes to insert it
|
||||
@param viewSublayerIndex The index in layer.sublayers (not view.subviews) at which to insert the view (use if we can use the view API) otherwise pass NSNotFound
|
||||
@param sublayerIndex The index in layer.sublayers at which to insert the layer (use if either parent or subnode is layer-backed) otherwise pass NSNotFound
|
||||
@param oldSubnode Remove this subnode before inserting; ok to be nil if no removal is desired
|
||||
*/
|
||||
- (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnodeIndex sublayerIndex:(NSInteger)sublayerIndex andRemoveSubnode:(ASDisplayNode *)oldSubnode
|
||||
- (void)_addSubnodeViewsAndLayers
|
||||
{
|
||||
if (subnodeIndex == NSNotFound) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(subnode, @"Cannot insert a nil subnode");
|
||||
if (!subnode) {
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNode *oldParent = [subnode _deallocSafeSupernode];
|
||||
// Disable appearance methods during move between supernodes, but make sure we restore their state after we do our thing
|
||||
BOOL isMovingEquivalentParents = disableNotificationsForMovingBetweenParents(oldParent, self);
|
||||
if (isMovingEquivalentParents) {
|
||||
[subnode __incrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
|
||||
[subnode _removeFromSupernode];
|
||||
[oldSubnode _removeFromSupernode];
|
||||
|
||||
if (!_subnodes)
|
||||
_subnodes = [[NSMutableArray alloc] init];
|
||||
ASDisplayNodeLogEvent(self, @"%@: %@", NSStringFromSelector(_cmd), subnode);
|
||||
[_subnodes insertObject:subnode atIndex:subnodeIndex];
|
||||
[subnode __setSupernode:self];
|
||||
|
||||
// Don't bother inserting the view/layer if in a rasterized subtree, because there are no layers in the hierarchy and none of this could possibly work.
|
||||
if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) {
|
||||
if (_layer) {
|
||||
ASDisplayNodeCAssertMainThread();
|
||||
|
||||
ASDisplayNodeAssert(sublayerIndex != NSNotFound, @"Should pass either a valid sublayerIndex");
|
||||
|
||||
if (sublayerIndex != NSNotFound) {
|
||||
BOOL canUseViewAPI = !subnode.isLayerBacked && !self.isLayerBacked;
|
||||
// If we can use view API, do. Due to an apple bug, -insertSubview:atIndex: actually wants a LAYER index, which we pass in
|
||||
if (canUseViewAPI && sublayerIndex != NSNotFound) {
|
||||
[_view insertSubview:subnode.view atIndex:sublayerIndex];
|
||||
} else if (sublayerIndex != NSNotFound) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wconversion"
|
||||
[_layer insertSublayer:subnode.layer atIndex:sublayerIndex];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
for (ASDisplayNode *node in [_subnodes copy]) {
|
||||
[self _addSubnodeSubviewOrSublayer:node];
|
||||
}
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(isMovingEquivalentParents == disableNotificationsForMovingBetweenParents(oldParent, self), @"Invariant violated");
|
||||
if (isMovingEquivalentParents) {
|
||||
[subnode __decrementVisibilityNotificationsDisabled];
|
||||
}
|
||||
- (void)_addSubnodeSubviewOrSublayer:(ASDisplayNode *)subnode
|
||||
{
|
||||
// Due to a bug in Apple's framework we have to use the layer index to insert a subview
|
||||
// so just use th ecount of the sublayers to add the subnode
|
||||
NSInteger idx = _layer.sublayers.count;
|
||||
[self _insertSubnodeSubviewOrSublayer:subnode atIndex:idx];
|
||||
}
|
||||
|
||||
- (void)replaceSubnode:(ASDisplayNode *)oldSubnode withSubnode:(ASDisplayNode *)replacementSubnode
|
||||
@ -1779,31 +1807,37 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
if (!replacementSubnode || [oldSubnode _deallocSafeSupernode] != self) {
|
||||
ASDisplayNodeAssert(0, @"Bad use of api. Invalid subnode to replace async.");
|
||||
if (replacementSubnode == nil) {
|
||||
ASDisplayNodeFailAssert(@"Invalid subnode to replace");
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(!(self.nodeLoaded && !oldSubnode.nodeLoaded), @"ASDisplayNode corruption bug. We have view loaded, but child node does not.");
|
||||
if ([oldSubnode _deallocSafeSupernode] != self) {
|
||||
ASDisplayNodeFailAssert(@"Old Subnode to replace must be a subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(!(self.nodeLoaded && !oldSubnode.nodeLoaded), @"We have view loaded, but child node does not.");
|
||||
ASDisplayNodeAssert(_subnodes, @"You should have subnodes if you have a subnode");
|
||||
|
||||
NSInteger subnodeIndex = [_subnodes indexOfObjectIdenticalTo:oldSubnode];
|
||||
NSInteger sublayerIndex = NSNotFound;
|
||||
|
||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the
|
||||
// hierarchy and none of this could possibly work.
|
||||
if (nodeIsInRasterizedTree(self) == NO) {
|
||||
if (_layer) {
|
||||
sublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:oldSubnode.layer];
|
||||
ASDisplayNodeAssert(sublayerIndex != NSNotFound, @"Somehow oldSubnode's supernode is self, yet we could not find it in our layers to replace");
|
||||
if (sublayerIndex == NSNotFound) return;
|
||||
if (sublayerIndex == NSNotFound) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self _insertSubnode:replacementSubnode atSubnodeIndex:subnodeIndex sublayerIndex:sublayerIndex andRemoveSubnode:oldSubnode];
|
||||
}
|
||||
|
||||
// This is just a convenience to avoid a bunch of conditionals
|
||||
static NSInteger incrementIfFound(NSInteger i) {
|
||||
return i == NSNotFound ? NSNotFound : i + 1;
|
||||
}
|
||||
|
||||
- (void)insertSubnode:(ASDisplayNode *)subnode belowSubnode:(ASDisplayNode *)below
|
||||
{
|
||||
// TODO: 2.0 Conversion: Reenable and fix within product code
|
||||
@ -1816,13 +1850,13 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
ASDisplayNodeAssert(subnode, @"Cannot insert a nil subnode");
|
||||
if (!subnode) {
|
||||
if (subnode == nil) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a nil subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert([below _deallocSafeSupernode] == self, @"Node to insert below must be a subnode");
|
||||
if ([below _deallocSafeSupernode] != self) {
|
||||
ASDisplayNodeFailAssert(@"Node to insert below must be a subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1831,13 +1865,21 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
NSInteger belowSubnodeIndex = [_subnodes indexOfObjectIdenticalTo:below];
|
||||
NSInteger belowSublayerIndex = NSNotFound;
|
||||
|
||||
|
||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the
|
||||
// hierarchy and none of this could possibly work.
|
||||
if (nodeIsInRasterizedTree(self) == NO) {
|
||||
if (_layer) {
|
||||
belowSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:below.layer];
|
||||
ASDisplayNodeAssert(belowSublayerIndex != NSNotFound, @"Somehow below's supernode is self, yet we could not find it in our layers to reference");
|
||||
if (belowSublayerIndex == NSNotFound)
|
||||
return;
|
||||
}
|
||||
// If the subnode is already in the subnodes array / sublayers and it's before the below node, removing it to insert it will mess up our calculation
|
||||
|
||||
ASDisplayNodeAssert(belowSubnodeIndex != NSNotFound, @"Couldn't find above in subnodes");
|
||||
|
||||
// If the subnode is already in the subnodes array / sublayers and it's before the below node, removing it to
|
||||
// insert it will mess up our calculation
|
||||
if ([subnode _deallocSafeSupernode] == self) {
|
||||
NSInteger currentIndexInSubnodes = [_subnodes indexOfObjectIdenticalTo:subnode];
|
||||
if (currentIndexInSubnodes < belowSubnodeIndex) {
|
||||
@ -1850,6 +1892,7 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(belowSubnodeIndex != NSNotFound, @"Couldn't find below in subnodes");
|
||||
|
||||
@ -1868,13 +1911,13 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
ASDisplayNodeAssert(subnode, @"Cannot insert a nil subnode");
|
||||
if (!subnode) {
|
||||
if (subnode == nil) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a nil subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert([above _deallocSafeSupernode] == self, @"Node to insert above must be a subnode");
|
||||
if ([above _deallocSafeSupernode] != self) {
|
||||
ASDisplayNodeFailAssert(@"Node to insert above must be a subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1883,17 +1926,20 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
NSInteger aboveSubnodeIndex = [_subnodes indexOfObjectIdenticalTo:above];
|
||||
NSInteger aboveSublayerIndex = NSNotFound;
|
||||
|
||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the hierarchy and none of this could possibly work.
|
||||
if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) {
|
||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the
|
||||
// hierarchy and none of this could possibly work.
|
||||
if (nodeIsInRasterizedTree(self) == NO) {
|
||||
if (_layer) {
|
||||
aboveSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:above.layer];
|
||||
ASDisplayNodeAssert(aboveSublayerIndex != NSNotFound, @"Somehow above's supernode is self, yet we could not find it in our layers to replace");
|
||||
if (aboveSublayerIndex == NSNotFound)
|
||||
return;
|
||||
}
|
||||
|
||||
ASDisplayNodeAssert(aboveSubnodeIndex != NSNotFound, @"Couldn't find above in subnodes");
|
||||
|
||||
// If the subnode is already in the subnodes array / sublayers and it's before the below node, removing it to insert it will mess up our calculation
|
||||
// If the subnode is already in the subnodes array / sublayers and it's before the below node, removing it to
|
||||
// insert it will mess up our calculation
|
||||
if ([subnode _deallocSafeSupernode] == self) {
|
||||
NSInteger currentIndexInSubnodes = [_subnodes indexOfObjectIdenticalTo:subnode];
|
||||
if (currentIndexInSubnodes <= aboveSubnodeIndex) {
|
||||
@ -1923,18 +1969,21 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
ASDN::MutexLocker l(__instanceLock__);
|
||||
|
||||
if (subnode == nil) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a nil subnode");
|
||||
return;
|
||||
}
|
||||
|
||||
if (idx > _subnodes.count || idx < 0) {
|
||||
ASDisplayNodeFailAssert(@"Cannot insert a subnode at index %zd. Count is %zd", idx, _subnodes.count);
|
||||
return;
|
||||
}
|
||||
|
||||
if (subnode == nil) {
|
||||
ASDisplayNodeFailAssert(@"Attempt to insert a nil subnode into node %@", self);
|
||||
return;
|
||||
}
|
||||
|
||||
NSInteger sublayerIndex = NSNotFound;
|
||||
|
||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, because there are no layers in the
|
||||
// hierarchy and none of this could possibly work.
|
||||
if (nodeIsInRasterizedTree(self) == NO) {
|
||||
// Account for potentially having other subviews
|
||||
if (_layer && idx == 0) {
|
||||
sublayerIndex = 0;
|
||||
@ -1944,35 +1993,11 @@ static NSInteger incrementIfFound(NSInteger i) {
|
||||
sublayerIndex = incrementIfFound([_layer.sublayers indexOfObjectIdenticalTo:positionInRelationTo.layer]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[self _insertSubnode:subnode atSubnodeIndex:idx sublayerIndex:sublayerIndex andRemoveSubnode:nil];
|
||||
}
|
||||
|
||||
|
||||
- (void)_addSubnodeSubviewOrSublayer:(ASDisplayNode *)subnode
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
ASDisplayNodeAssert(self.nodeLoaded, @"_addSubnodeSubview: should never be called before our own view is created");
|
||||
|
||||
BOOL canUseViewAPI = !self.isLayerBacked && !subnode.isLayerBacked;
|
||||
if (canUseViewAPI) {
|
||||
[_view addSubview:subnode.view];
|
||||
} else {
|
||||
// Disallow subviews in a layer-backed node
|
||||
ASDisplayNodeAssert(subnode.isLayerBacked, @"Cannot add a subview to a layer-backed node; only sublayers permitted.");
|
||||
[_layer addSublayer:subnode.layer];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_addSubnodeViewsAndLayers
|
||||
{
|
||||
ASDisplayNodeAssertMainThread();
|
||||
|
||||
for (ASDisplayNode *node in [_subnodes copy]) {
|
||||
[self _addSubnodeSubviewOrSublayer:node];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)_removeSubnode:(ASDisplayNode *)subnode
|
||||
{
|
||||
ASDisplayNodeAssertThreadAffinity(self);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user