Home asdisplaynode-underthescene
Post
Cancel

asdisplaynode-underthescene

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;
  }
}
This post is licensed under CC BY 4.0 by the author.