Skip to content

Commit

Permalink
[ASDisplayNode] Consolidate main thread initialization and allow apps…
Browse files Browse the repository at this point in the history
… to invoke it manually instead of +load. (#798)

* - [ASDisplayNode] Consolidate main thread initialization and allow apps to invoke it manually instead of +load.

Additionally this has a few minor fixes for Yoga support, and adds some basic
but universally valuable callbacks like -nodeDidLoad to ASNodeController.

* Small fix for handling _layoutVersion.

* Remove poking the scale accessor
  • Loading branch information
appleguy authored and Adlai-Holler committed Feb 26, 2018
1 parent 236cdd7 commit 223f1c9
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 18 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## master
* Add your own contributions to the next release on the line below this with your name.
- [ASDisplayNode] Consolidate main thread initialization and allow apps to invoke it manually instead of +load.
- [ASRunloopQueue] Introduce new runloop queue(ASCATransactionQueue) to coalesce Interface state update calls for view controller transitions.
- [ASRangeController] Fix stability of "minimum" rangeMode if the app has more than one layout before scrolling.
- **Important** ASDisplayNode's cornerRadius is a new thread-safe bridged property that should be preferred over CALayer's. Use the latter at your own risk! [Huy Nguyen](https://github.com/nguyenhuy) [#749](https://github.com/TextureGroup/Texture/pull/749).
Expand Down
2 changes: 2 additions & 0 deletions Source/ASDisplayNode+Beta.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ extern void ASDisplayNodePerformBlockOnEveryYogaChild(ASDisplayNode * _Nullable
@interface ASLayoutElementStyle (Yoga)

- (YGNodeRef)yogaNodeCreateIfNeeded;
- (void)destroyYogaNode;

@property (nonatomic, assign, readonly) YGNodeRef yogaNode;

@property (nonatomic, assign, readwrite) ASStackLayoutDirection flexDirection;
Expand Down
7 changes: 7 additions & 0 deletions Source/ASDisplayNode+Subclasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (void)nodeDidLayout;

/**
* @abstract Called when the node loads.
* @discussion Can be used for operations that are performed after the node's view is available.
* @note This method is guaranteed to be called on main.
*/
- (void)nodeDidLoad;

@end

@interface ASDisplayNode (Subclassing) <ASInterfaceStateDelegate>
Expand Down
20 changes: 17 additions & 3 deletions Source/ASDisplayNode+Yoga.mm
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ - (ASLayout *)layoutForYogaNode

- (void)setupYogaCalculatedLayout
{
ASDN::MutexLocker l(__instanceLock__);

YGNodeRef yogaNode = self.style.yogaNode;
uint32_t childCount = YGNodeGetChildCount(yogaNode);
ASDisplayNodeAssert(childCount == self.yogaChildren.count,
Expand Down Expand Up @@ -210,7 +212,10 @@ - (void)setupYogaCalculatedLayout
parentSize.width = YGNodeLayoutGetWidth(parentNode);
parentSize.height = YGNodeLayoutGetHeight(parentNode);
}
_pendingDisplayNodeLayout = std::make_shared<ASDisplayNodeLayout>(layout, ASSizeRangeUnconstrained, parentSize, 0);
// For the root node in a Yoga tree, make sure to preserve the constrainedSize originally provided.
// This will be used for all relayouts triggered by children, since they escalate to root.
ASSizeRange range = parentNode ? ASSizeRangeUnconstrained : self.constrainedSizeForCalculatedLayout;
_pendingDisplayNodeLayout = std::make_shared<ASDisplayNodeLayout>(layout, range, parentSize, _layoutVersion);
}
}

Expand All @@ -235,9 +240,18 @@ - (void)updateYogaMeasureFuncIfNeeded
- (void)invalidateCalculatedYogaLayout
{
YGNodeRef yogaNode = self.style.yogaNode;
if (yogaNode && YGNodeGetMeasureFunc(yogaNode)) {
if (yogaNode && [self shouldHaveYogaMeasureFunc]) {
// Yoga internally asserts that MarkDirty() may only be called on nodes with a measurement function.
BOOL needsTemporaryMeasureFunc = (YGNodeGetMeasureFunc(yogaNode) == NULL);
if (needsTemporaryMeasureFunc) {
ASDisplayNodeAssert(self.yogaLayoutInProgress == NO,
@"shouldHaveYogaMeasureFunc == YES, and inside a layout pass, but no measure func pointer! %@", self);
YGNodeSetMeasureFunc(yogaNode, &ASLayoutElementYogaMeasureFunc);
}
YGNodeMarkDirty(yogaNode);
if (needsTemporaryMeasureFunc) {
YGNodeSetMeasureFunc(yogaNode, NULL);
}
}
self.yogaCalculatedLayout = nil;
}
Expand Down Expand Up @@ -305,7 +319,7 @@ - (void)calculateLayoutFromYogaRoot:(ASSizeRange)rootConstrainedSize
NSLog(@"node = %@", node);
NSLog(@"style = %@", node.style);
NSLog(@"layout = %@", node.yogaCalculatedLayout);
YGNodePrint(node.style.yogaNode, (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsLayout));
YGNodePrint(node.yogaNode, (YGPrintOptions)(YGPrintOptionsStyle | YGPrintOptionsLayout));
});
}
#endif /* YOGA_LAYOUT_LOGGING */
Expand Down
9 changes: 9 additions & 0 deletions Source/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,13 @@ + (void)initialize
class_replaceMethod(self, @selector(_staticInitialize), staticInitialize, "v:@");
}

#if !AS_INITIALIZE_FRAMEWORK_MANUALLY
+ (void)load
{
ASInitializeFrameworkMainThread();
}
#endif

+ (Class)viewClass
{
return [_ASDisplayView class];
Expand Down Expand Up @@ -631,6 +638,8 @@ - (void)_didLoad
for (ASDisplayNodeDidLoadBlock block in onDidLoadBlocks) {
block(self);
}

[_interfaceStateDelegate nodeDidLoad];
}

- (void)didLoad
Expand Down
3 changes: 3 additions & 0 deletions Source/ASNodeController+Beta.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
- (void)loadNode;

// for descriptions see <ASInterfaceState> definition
- (void)nodeDidLoad ASDISPLAYNODE_REQUIRES_SUPER;
- (void)nodeDidLayout ASDISPLAYNODE_REQUIRES_SUPER;

- (void)didEnterVisibleState ASDISPLAYNODE_REQUIRES_SUPER;
- (void)didExitVisibleState ASDISPLAYNODE_REQUIRES_SUPER;

Expand Down
1 change: 1 addition & 0 deletions Source/ASNodeController+Beta.m
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ - (void)setShouldInvertStrongReference:(BOOL)shouldInvertStrongReference
}

// subclass overrides
- (void)nodeDidLoad {}
- (void)nodeDidLayout {}

- (void)didEnterVisibleState {}
Expand Down
1 change: 1 addition & 0 deletions Source/AsyncDisplayKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
//

#import <AsyncDisplayKit/ASAvailability.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <AsyncDisplayKit/ASDisplayNode.h>
#import <AsyncDisplayKit/ASDisplayNode+Ancestry.h>
#import <AsyncDisplayKit/ASDisplayNode+Convenience.h>
Expand Down
9 changes: 9 additions & 0 deletions Source/Private/ASInternalHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ NS_ASSUME_NONNULL_BEGIN

ASDISPLAYNODE_EXTERN_C_BEGIN

void ASInitializeFrameworkMainThread(void);

BOOL ASDefaultAllowsGroupOpacity(void);
BOOL ASDefaultAllowsEdgeAntialiasing(void);

BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector);
BOOL ASSubclassOverridesClassSelector(Class superclass, Class subclass, SEL selector);

Expand Down Expand Up @@ -100,3 +105,7 @@ ASDISPLAYNODE_INLINE void ASBoundsAndPositionForFrame(CGRect rect, CGPoint origi
@end

NS_ASSUME_NONNULL_END

#ifndef AS_INITIALIZE_FRAMEWORK_MANUALLY
#define AS_INITIALIZE_FRAMEWORK_MANUALLY 0
#endif
22 changes: 22 additions & 0 deletions Source/Private/ASInternalHelpers.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,28 @@
#import <AsyncDisplayKit/ASRunLoopQueue.h>
#import <AsyncDisplayKit/ASThread.h>

static BOOL defaultAllowsGroupOpacity = YES;
static BOOL defaultAllowsEdgeAntialiasing = NO;

void ASInitializeFrameworkMainThread(void)
{
ASDisplayNodeThreadIsMain();
// Ensure these values are cached on the main thread before needed in the background.
CALayer *layer = [[[UIView alloc] init] layer];
defaultAllowsGroupOpacity = layer.allowsGroupOpacity;
defaultAllowsEdgeAntialiasing = layer.allowsEdgeAntialiasing;
}

BOOL ASDefaultAllowsGroupOpacity(void)
{
return defaultAllowsGroupOpacity;
}

BOOL ASDefaultAllowsEdgeAntialiasing(void)
{
return defaultAllowsEdgeAntialiasing;
}

BOOL ASSubclassOverridesSelector(Class superclass, Class subclass, SEL selector)
{
if (superclass == subclass) return NO; // Even if the class implements the selector, it doesn't override itself.
Expand Down
17 changes: 2 additions & 15 deletions Source/Private/_ASPendingState.mm
Original file line number Diff line number Diff line change
Expand Up @@ -212,19 +212,6 @@ ASDISPLAYNODE_INLINE void ASPendingStateApplyMetricsToLayer(_ASPendingState *sta

static CGColorRef blackColorRef = NULL;
static UIColor *defaultTintColor = nil;
static BOOL defaultAllowsGroupOpacity = YES;
static BOOL defaultAllowsEdgeAntialiasing = NO;

+ (void)load
{
// Create temporary view to read default values that are based on linked SDK and Info.plist values
// Ensure this values cached on the main thread before needed
ASDisplayNodeCAssertMainThread();
UIView *view = [[UIView alloc] init];
defaultAllowsGroupOpacity = view.layer.allowsGroupOpacity;
defaultAllowsEdgeAntialiasing = view.layer.allowsEdgeAntialiasing;
}


- (instancetype)init
{
Expand All @@ -251,8 +238,8 @@ - (instancetype)init
tintColor = defaultTintColor;
isHidden = NO;
needsDisplayOnBoundsChange = NO;
allowsGroupOpacity = defaultAllowsGroupOpacity;
allowsEdgeAntialiasing = defaultAllowsEdgeAntialiasing;
allowsGroupOpacity = ASDefaultAllowsGroupOpacity();
allowsEdgeAntialiasing = ASDefaultAllowsEdgeAntialiasing();
autoresizesSubviews = YES;
alpha = 1.0f;
cornerRadius = 0.0f;
Expand Down

0 comments on commit 223f1c9

Please sign in to comment.