From f8e135a1bee0c98ce0165c25a87699114476e15e Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Thu, 1 Sep 2016 16:09:59 -0700 Subject: [PATCH] Add old transition API back but allow call from background thread (#2135) --- AsyncDisplayKit/ASCellNode.mm | 39 ++++++------------ AsyncDisplayKit/ASDisplayNode+Deprecated.h | 41 ------------------- AsyncDisplayKit/ASDisplayNode.h | 11 ++++- AsyncDisplayKit/ASDisplayNode.mm | 39 ++++++++---------- .../ASDisplayNodeImplicitHierarchyTests.m | 4 +- .../Sample/ViewController.m | 2 +- 6 files changed, 43 insertions(+), 93 deletions(-) diff --git a/AsyncDisplayKit/ASCellNode.mm b/AsyncDisplayKit/ASCellNode.mm index 4ea7a868b0..a096a233dd 100644 --- a/AsyncDisplayKit/ASCellNode.mm +++ b/AsyncDisplayKit/ASCellNode.mm @@ -115,35 +115,13 @@ [self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize]; } -- (void)transitionLayoutAnimated:(BOOL)animated - measurementCompletion:(void (^)())completion -{ - CGSize oldSize = self.calculatedSize; - [super transitionLayoutAnimated:animated - measurementCompletion:^{ - [self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize]; - if (completion) { - completion(); - } - } - ]; -} - -//Deprecated - (void)transitionLayoutWithAnimation:(BOOL)animated shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(void(^)())completion -{ - [self transitionLayoutAnimated:animated measurementCompletion:completion]; -} - -- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize - animated:(BOOL)animated - measurementCompletion:(void (^)())completion { CGSize oldSize = self.calculatedSize; - [super transitionLayoutWithSizeRange:constrainedSize - animated:animated + [super transitionLayoutWithAnimation:animated + shouldMeasureAsync:shouldMeasureAsync measurementCompletion:^{ [self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize]; if (completion) { @@ -153,13 +131,22 @@ ]; } -//Deprecated - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(void(^)())completion { - [self transitionLayoutWithSizeRange:constrainedSize animated:animated measurementCompletion:completion]; + CGSize oldSize = self.calculatedSize; + [super transitionLayoutWithSizeRange:constrainedSize + animated:animated + shouldMeasureAsync:shouldMeasureAsync + measurementCompletion:^{ + [self didRelayoutFromOldSize:oldSize toNewSize:self.calculatedSize]; + if (completion) { + completion(); + } + } + ]; } - (void)didRelayoutFromOldSize:(CGSize)oldSize toNewSize:(CGSize)newSize diff --git a/AsyncDisplayKit/ASDisplayNode+Deprecated.h b/AsyncDisplayKit/ASDisplayNode+Deprecated.h index 2a3bb4cd30..80c84a770a 100644 --- a/AsyncDisplayKit/ASDisplayNode+Deprecated.h +++ b/AsyncDisplayKit/ASDisplayNode+Deprecated.h @@ -54,47 +54,6 @@ */ - (void)loadStateDidChange:(BOOL)inLoadState ASDISPLAYNODE_REQUIRES_SUPER ASDISPLAYNODE_DEPRECATED; -/** - * @abstract Transitions the current layout with a new constrained size. Must be called on main thread. - * - * @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`. - * @param shouldMeasureAsync Measure the layout asynchronously. - * @param measurementCompletion Optional completion block called only if a new layout is calculated. - * It is called on main, right after the measurement and before -animateLayoutTransition:. - * - * @discussion If the passed constrainedSize is the the same as the node's current constrained size, this method is noop. - * - * @see animateLayoutTransition: - * - * @deprecated Deprecated in version 2.0: Use transitionLayoutWithSizeRange:animated:measurementCompletion:. - * shouldMeasureAsync is enabled by default now. - * - */ -- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize - animated:(BOOL)animated - shouldMeasureAsync:(BOOL)shouldMeasureAsync - measurementCompletion:(nullable void(^)())completion ASDISPLAYNODE_DEPRECATED; - - -/** - * @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread. - * - * @discussion It is called right after the measurement and before -animateLayoutTransition:. - * - * @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`. - * @param shouldMeasureAsync Measure the layout asynchronously. - * @param measurementCompletion Optional completion block called only if a new layout is calculated. - * - * @see animateLayoutTransition: - * - * @deprecated Deprecated in version 2.0: Use transitionLayoutAnimated:measurementCompletion: - * shouldMeasureAsync is enabled by default now. - * - */ -- (void)transitionLayoutWithAnimation:(BOOL)animated - shouldMeasureAsync:(BOOL)shouldMeasureAsync - measurementCompletion:(nullable void(^)())completion ASDISPLAYNODE_DEPRECATED; - /** * @abstract Cancels all performing layout transitions. Can be called on any thread. * diff --git a/AsyncDisplayKit/ASDisplayNode.h b/AsyncDisplayKit/ASDisplayNode.h index 3274ea8072..c2e5fbef85 100644 --- a/AsyncDisplayKit/ASDisplayNode.h +++ b/AsyncDisplayKit/ASDisplayNode.h @@ -782,27 +782,34 @@ NS_ASSUME_NONNULL_BEGIN * @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`. * @param shouldMeasureAsync Measure the layout asynchronously. * @param measurementCompletion Optional completion block called only if a new layout is calculated. + * It is called on main, right after the measurement and before -animateLayoutTransition:. * - * @discussion It is called on main, right after the measurement and before -animateLayoutTransition:. If the passed constrainedSize is the the same as the node's current constrained size, this method is noop. + * @discussion If the passed constrainedSize is the the same as the node's current constrained size, this method is noop. If passed YES to shouldMeasureAsync it's guaranteed that measurement is happening on a background thread, otherwise measaurement will happen on the thread that the method was called on. The measurementCompletion callback is always called on the main thread right after the measurement and before -animateLayoutTransition:. * * @see animateLayoutTransition: + * */ - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated + shouldMeasureAsync:(BOOL)shouldMeasureAsync measurementCompletion:(nullable void(^)())completion; + /** * @abstract Invalidates the current layout and begins a relayout of the node with the current `constrainedSize`. Must be called on main thread. * * @discussion It is called right after the measurement and before -animateLayoutTransition:. * * @param animated Animation is optional, but will still proceed through your `animateLayoutTransition` implementation with `isAnimated == NO`. + * @param shouldMeasureAsync Measure the layout asynchronously. * @param measurementCompletion Optional completion block called only if a new layout is calculated. * * @see animateLayoutTransition: * */ -- (void)transitionLayoutAnimated:(BOOL)animated measurementCompletion:(nullable void(^)())completion; +- (void)transitionLayoutWithAnimation:(BOOL)animated + shouldMeasureAsync:(BOOL)shouldMeasureAsync + measurementCompletion:(nullable void(^)())completion; /** * @abstract Cancels all performing layout transitions. Can be called on any thread. diff --git a/AsyncDisplayKit/ASDisplayNode.mm b/AsyncDisplayKit/ASDisplayNode.mm index c353908628..e125770588 100644 --- a/AsyncDisplayKit/ASDisplayNode.mm +++ b/AsyncDisplayKit/ASDisplayNode.mm @@ -723,7 +723,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) #pragma mark - Layout Transition -- (void)transitionLayoutAnimated:(BOOL)animated measurementCompletion:(void (^)())completion +- (void)transitionLayoutWithAnimation:(BOOL)animated + shouldMeasureAsync:(BOOL)shouldMeasureAsync + measurementCompletion:(void(^)())completion { if (_calculatedLayout == nil) { // constrainedSizeRange returns a struct and is invalid to call on nil. @@ -734,15 +736,18 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) [self invalidateCalculatedLayout]; [self transitionLayoutWithSizeRange:_calculatedLayout.constrainedSizeRange animated:animated + shouldMeasureAsync:shouldMeasureAsync measurementCompletion:completion]; + } - (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize animated:(BOOL)animated - measurementCompletion:(void (^)())completion + shouldMeasureAsync:(BOOL)shouldMeasureAsync + measurementCompletion:(void(^)())completion { - ASDisplayNodeAssertMainThread(); - if (! [self shouldMeasureWithSizeRange:constrainedSize]) { + // Passed constrainedSize is the the same as the node's current constrained size it's a noop + if ([self shouldMeasureWithSizeRange:constrainedSize] == NO) { return; } @@ -759,7 +764,8 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) node.pendingTransitionID = transitionID; }); - ASPerformBlockOnBackgroundThread(^{ + + void (^transitionBlock)(void) = ^{ if ([self _shouldAbortTransitionWithID:transitionID]) { return; } @@ -821,7 +827,13 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c) // Kick off animating the layout transition [self animateLayoutTransition:_pendingLayoutTransitionContext]; }); - }); + }; + + if (shouldMeasureAsync) { + ASPerformBlockOnBackgroundThread(transitionBlock); + } else { + transitionBlock(); + } } - (void)cancelLayoutTransition @@ -3317,21 +3329,6 @@ static const char *ASDisplayNodeAssociatedNodeKey = "ASAssociatedNode"; @implementation ASDisplayNode (Deprecated) -- (void)transitionLayoutWithAnimation:(BOOL)animated - shouldMeasureAsync:(BOOL)shouldMeasureAsync - measurementCompletion:(void(^)())completion -{ - [self transitionLayoutAnimated:animated measurementCompletion:completion]; -} - -- (void)transitionLayoutWithSizeRange:(ASSizeRange)constrainedSize - animated:(BOOL)animated - shouldMeasureAsync:(BOOL)shouldMeasureAsync - measurementCompletion:(void(^)())completion -{ - [self transitionLayoutWithSizeRange:constrainedSize animated:animated measurementCompletion:completion]; -} - - (void)cancelLayoutTransitionsInProgress { [self cancelLayoutTransition]; diff --git a/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m b/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m index 5025f6fc9d..1d5f0a0097 100644 --- a/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m +++ b/AsyncDisplayKitTests/ASDisplayNodeImplicitHierarchyTests.m @@ -126,7 +126,7 @@ XCTestExpectation *expectation = [self expectationWithDescription:@"Call measurement completion block on main"]; - [displayNode transitionLayoutWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero) animated:YES measurementCompletion:^{ + [displayNode transitionLayoutWithSizeRange:ASSizeRangeMake(CGSizeZero, CGSizeZero) animated:YES shouldMeasureAsync:YES measurementCompletion:^{ XCTAssertTrue(ASDisplayNodeThreadIsMain(), @"Measurement completion block should be called on main thread"); [expectation fulfill]; }]; @@ -207,7 +207,7 @@ node.layoutState = @2; [node invalidateCalculatedLayout]; - [node transitionLayoutAnimated:YES measurementCompletion:^{ + [node transitionLayoutWithAnimation:YES shouldMeasureAsync:YES measurementCompletion:^{ // Push this to the next runloop to let async insertion / removing of nodes finished before checking dispatch_async(dispatch_get_main_queue(), ^{ XCTAssertEqual(node.subnodes[0], node2); diff --git a/examples/ASDKLayoutTransition/Sample/ViewController.m b/examples/ASDKLayoutTransition/Sample/ViewController.m index 48f1ffeba1..1bda2a9307 100644 --- a/examples/ASDKLayoutTransition/Sample/ViewController.m +++ b/examples/ASDKLayoutTransition/Sample/ViewController.m @@ -89,7 +89,7 @@ { self.enabled = !self.enabled; - [self transitionLayoutAnimated:YES measurementCompletion:nil]; + [self transitionLayoutWithAnimation:YES shouldMeasureAsync:NO measurementCompletion:nil]; }