ASDisplayNode.mm
view
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
- (UIView *)view
{
AS::UniqueLock l(__instanceLock__);
ASDisplayNodeAssert(!_flags.layerBacked, @"Call to -view undefined on layer-backed nodes");
BOOL isLayerBacked = _flags.layerBacked;
if (isLayerBacked) {
return nil;
}
if (_view != nil) {
return _view;
}
if (![self _locked_shouldLoadViewOrLayer]) {
return nil;
}
// Loading a view needs to happen on the main thread
ASDisplayNodeAssertMainThread();
[self _locked_loadViewOrLayer];
// FIXME: Ideally we'd call this as soon as the node receives -setNeedsLayout
// but automatic subnode management would require us to modify the node tree
// in the background on a loaded node, which isn't currently supported.
if (_pendingViewState.hasSetNeedsLayout) {
// Need to unlock before calling setNeedsLayout to avoid deadlocks.
l.unlock();
[self __setNeedsLayout];
l.lock();
}
[self _locked_applyPendingStateToViewOrLayer];
// The following methods should not be called with a lock
l.unlock();
// No need for the lock as accessing the subviews or layers are always happening on main
[self _addSubnodeViewsAndLayers];
// A subclass hook should never be called with a lock
[self _didLoad];
return _view;
}
layer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
- (CALayer *)layer
{
AS::UniqueLock l(__instanceLock__);
if (_layer != nil) {
return _layer;
}
if (![self _locked_shouldLoadViewOrLayer]) {
return nil;
}
// Loading a layer needs to happen on the main thread
ASDisplayNodeAssertMainThread();
[self _locked_loadViewOrLayer];
CALayer *layer = _layer;
// FIXME: Ideally we'd call this as soon as the node receives -setNeedsLayout
// but automatic subnode management would require us to modify the node tree
// in the background on a loaded node, which isn't currently supported.
if (_pendingViewState.hasSetNeedsLayout) {
// Need to unlock before calling setNeedsLayout to avoid deadlocks.
l.unlock();
[self __setNeedsLayout];
l.lock();
}
[self _locked_applyPendingStateToViewOrLayer];
// The following methods should not be called with a lock
l.unlock();
// No need for the lock as accessing the subviews or layers are always happening on main
[self _addSubnodeViewsAndLayers];
// A subclass hook should never be called with a lock
[self _didLoad];
return layer;
}
asyncLayer
1
2
3
4
5
- (_ASDisplayLayer *)asyncLayer
{
MutexLocker l(__instanceLock__);
return [self _locked_asyncLayer];
}
_locked_asyncLayer
1
2
3
4
5
- (_ASDisplayLayer *)_locked_asyncLayer
{
ASAssertLocked(__instanceLock__);
return [_layer isKindOfClass:[_ASDisplayLayer class]] ? (_ASDisplayLayer *)_layer : nil;
}
isLayerBacked
1
2
3
4
5
- (BOOL)isLayerBacked
{
MutexLocker l(__instanceLock__);
return _flags.layerBacked;
}
supportsLayerBacking
- (BOOL)supportsLayerBacking
{
MutexLocker l(__instanceLock__);
return !checkFlag(Synchronous) && !_flags.viewEverHadAGestureRecognizerAttached && _viewClass == [_ASDisplayView class] && _layerClass == [_ASDisplayLayer class];
}
shouldAnimateSizeChanges
1
2
3
4
5
- (BOOL)shouldAnimateSizeChanges
{
MutexLocker l(__instanceLock__);
return _flags.shouldAnimateSizeChanges;
}
threadSafeBounds
1
2
3
4
5
- (CGRect)threadSafeBounds
{
MutexLocker l(__instanceLock__);
return [self _locked_threadSafeBounds];
}
nodeViewDidAddGestureRecognizer
1
2
3
4
5
- (void)nodeViewDidAddGestureRecognizer
{
MutexLocker l(__instanceLock__);
_flags.viewEverHadAGestureRecognizerAttached = YES;
}
setFallbackSafeAreaInsets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
- (void)setFallbackSafeAreaInsets:(UIEdgeInsets)insets
{
BOOL needsManualUpdate;
BOOL updatesLayoutMargins;
{
MutexLocker l(__instanceLock__);
ASDisplayNodeAssertThreadAffinity(self);
if (UIEdgeInsetsEqualToEdgeInsets(insets, _fallbackSafeAreaInsets)) {
return;
}
_fallbackSafeAreaInsets = insets;
needsManualUpdate = !AS_AT_LEAST_IOS11 || _flags.layerBacked;
updatesLayoutMargins = needsManualUpdate && [self _locked_insetsLayoutMarginsFromSafeArea];
}
if (needsManualUpdate) {
[self safeAreaInsetsDidChange];
}
if (updatesLayoutMargins) {
[self layoutMarginsDidChange];
}
}
_fallbackUpdateSafeAreaOnChildren
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- (void)_fallbackUpdateSafeAreaOnChildren
{
ASDisplayNodeAssertThreadAffinity(self);
UIEdgeInsets insets = self.safeAreaInsets;
CGRect bounds = self.bounds;
for (ASDisplayNode *child in self.subnodes) {
if (AS_AT_LEAST_IOS11 && !child.layerBacked) {
// In iOS 11 view-backed nodes already know what their safe area is.
continue;
}
if (child.viewControllerRoot) {
// Its safe area is controlled by a view controller. Don't override it.
continue;
}
CGRect childFrame = child.frame;
UIEdgeInsets childInsets = UIEdgeInsetsMake(MAX(insets.top - (CGRectGetMinY(childFrame) - CGRectGetMinY(bounds)), 0),
MAX(insets.left - (CGRectGetMinX(childFrame) - CGRectGetMinX(bounds)), 0),
MAX(insets.bottom - (CGRectGetMaxY(bounds) - CGRectGetMaxY(childFrame)), 0),
MAX(insets.right - (CGRectGetMaxX(bounds) - CGRectGetMaxX(childFrame)), 0));
child.fallbackSafeAreaInsets = childInsets;
}
}
isViewControllerRoot
1
2
3
4
5
- (BOOL)isViewControllerRoot
{
MutexLocker l(__instanceLock__);
return _isViewControllerRoot;
}
automaticallyRelayoutOnSafeAreaChanges
1
2
3
4
5
6
- (BOOL)automaticallyRelayoutOnSafeAreaChanges
{
MutexLocker l(__instanceLock__);
return _automaticallyRelayoutOnSafeAreaChanges;
}
automaticallyRelayoutOnLayoutMarginsChanges
1
2
3
4
5
- (BOOL)automaticallyRelayoutOnLayoutMarginsChanges
{
MutexLocker l(__instanceLock__);
return _automaticallyRelayoutOnLayoutMarginsChanges;
}
__setNodeController
1
2
3
4
5
6
7
8
9
10
11
- (void)__setNodeController:(ASNodeController *)controller
{
// See docs for why we don't lock.
if (controller.shouldInvertStrongReference) {
_strongNodeController = controller;
_weakNodeController = nil;
} else {
_weakNodeController = controller;
_strongNodeController = nil;
}
}