Skip to content

Commit

Permalink
Remove unused methods.
Browse files Browse the repository at this point in the history
`-[ASDisplayNode addSubnodeAsynchronously::]` and
`-replaceSubnodeAsynchronously:::` are unused and confusingly increase
AsyncDisplayKit's API surface.  `-addSubnode:` and friends are
thread-safe and can be used on background threads, so removing these
methods does not constitute a decrease in functionality.
  • Loading branch information
secretiverhyme committed Sep 29, 2014
1 parent c51a58c commit af6c11a
Show file tree
Hide file tree
Showing 3 changed files with 0 additions and 272 deletions.
26 changes: 0 additions & 26 deletions AsyncDisplayKit/ASDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,32 +221,6 @@
*/
- (void)replaceSubnode:(ASDisplayNode *)subnode withSubnode:(ASDisplayNode *)replacementSubnode;

/**
* @abstract Add a subnode, but have it size asynchronously on a background queue.
*
* @param subnode The unsized subnode to insert into the view hierarchy
* @param completion The completion callback will be called on the main queue after the subnode has been inserted in
* place of the placeholder.
*
* @return A placeholder node is inserted into the hierarchy where the node will be. The placeholder can be moved around
* in the hiercharchy while the view is sizing. Once sizing is complete on the background queue, this placeholder will
* be removed and the replacement will be put at its place.
*/
- (ASDisplayNode *)addSubnodeAsynchronously:(ASDisplayNode *)subnode
completion:(void(^)(ASDisplayNode *replacement))completion;

/**
* @abstract Replace a subnode, but have it size asynchronously on a background queue.
*
* @param subnode A subnode of self.
* @param replacementSubnode A node with which to replace subnode.
* @param completion The completion callback will be called on the main queue after the replacementSubnode has replaced
* subnode.
*/
- (void)replaceSubnodeAsynchronously:(ASDisplayNode *)subnode
withNode:(ASDisplayNode *)replacementSubnode
completion:(void(^)(BOOL cancelled, ASDisplayNode *replacement, ASDisplayNode *oldSubnode))completion;

/**
* @abstract Remove this node from its supernode.
*
Expand Down
85 changes: 0 additions & 85 deletions AsyncDisplayKit/ASDisplayNode.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1401,91 +1401,6 @@ - (void)_enqueueAsyncSizingWithSentinel:(ASSentinel *)sentinel completion:(void(

}

- (void)replaceSubnodeAsynchronously:(ASDisplayNode *)old withNode:(ASDisplayNode *)replacement completion:(void(^)(BOOL cancelled, ASDisplayNode *replacement, ASDisplayNode *oldSubnode))completion
{

ASDisplayNodeAssert(old.supernode == self, @"Must replace something that is actually a subnode. You passed: %@", old);
ASDisplayNodeAssert(!replacement.nodeLoaded, @"Can't async size something that already has a view, since we currently have no way to convert a viewed node into a viewless one...");

// If we're already marked for replacement, cancel the pending request
ASSentinel *sentinel = [old _asyncReplaceSentinel];
uint32_t sentinelValue = [sentinel increment];

// Enqueue async sizing on our argument
[replacement _enqueueAsyncSizingWithSentinel:sentinel completion:^(ASDisplayNode *replacementCompletedNode) {
// Sizing is done; swap with our other view
// Check sentinel one more time in case it changed during sizing
if (replacementCompletedNode && sentinel.value == sentinelValue) {
if (old.supernode) {
if (old.supernode.inWindow) {
// Now wait for async display before notifying delegate that replacement is complete

// When async sizing is complete, add subnode below placeholder with 0 alpha
CGFloat replacementAlpha = replacement.alpha;
BOOL wasAsyncTransactionContainer = replacement.asyncdisplaykit_asyncTransactionContainer;
[old.supernode insertSubnode:replacement belowSubnode:old];

replacementCompletedNode.alpha = 0.0;
replacementCompletedNode.asyncdisplaykit_asyncTransactionContainer = YES;

ASDisplayNodeCAssert(replacementCompletedNode.nodeLoaded, @".layer shouldn't be the thing to load the view");

[replacement.layer.asyncdisplaykit_asyncTransaction addCompletionBlock:^(id<NSObject> unused, BOOL canceled) {
ASDisplayNodeCAssertMainThread();

canceled |= (sentinel.value != sentinelValue);

replacementCompletedNode.alpha = replacementAlpha;
replacementCompletedNode.asyncdisplaykit_asyncTransactionContainer = wasAsyncTransactionContainer;

if (!canceled) {
[old removeFromSupernode];
} else {
[replacementCompletedNode removeFromSupernode];
}

completion(canceled, replacementCompletedNode, old);
}];
} else {
// Not in window, don't wait for async display
[old.supernode replaceSubnode:old withSubnode:replacement];
completion(NO, replacementCompletedNode, old);
}

} else { // Old has been moved no longer to be in the hierarchy
// TODO: add code to removeFromSupernode and hook UIView methods to cancel sentinel here?
@throw [NSException exceptionWithName:NSInvalidArgumentException reason:@"Tried to replaceSubnodeAsynchronously an ASDisplayNode, but then removed it from the hierarchy... what did you mean?" userInfo:nil];

completion(NO, replacementCompletedNode, old);
}
} else { // If we were cancelled
completion(YES, nil, nil);
}
}];


}

- (ASDisplayNode *)addSubnodeAsynchronously:(ASDisplayNode *)replacement completion:(void(^)(ASDisplayNode *fullySizedSubnode))completion
{
ASDisplayNodeAssertThreadAffinity(self);

// Create a placeholder ASDisplayNode that saves this guy's place in the view hierarchy for when things return later
ASDisplayNode *placeholder = [[ASDisplayNode alloc] init];

[self addSubnode:placeholder];
[self replaceSubnodeAsynchronously:placeholder withNode:replacement completion:^(BOOL cancelled, ASDisplayNode *replacementBlock, ASDisplayNode *placeholderBlock) {
if (replacementBlock && placeholderBlock && !cancelled) {
[placeholderBlock removeFromSupernode];
completion(replacementBlock);
} else {
[placeholderBlock removeFromSupernode];
}
}];

return placeholder;
}

@end

@implementation ASDisplayNode (Debugging)
Expand Down
161 changes: 0 additions & 161 deletions AsyncDisplayKitTests/ASDisplayNodeTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -914,167 +914,6 @@ - (void)checkReplaceSubnodeWithView:(BOOL)loaded layerBacked:(BOOL)isLayerBacked
[d release];
}

- (void)testAddSubnodeAsync
{

ASTestDisplayNode *parent = [[ASTestDisplayNode alloc] init];

__block BOOL calculateSizeCalled = NO;
__block CGSize passedInSize;
__block BOOL sizeCalculatedOnMainThread;
ASTestDisplayNode *nodeToAddAsync = [[ASTestDisplayNode alloc] init];
nodeToAddAsync.bounds = CGRectMake(100, 40, 42, 56);
nodeToAddAsync.calculateSizeBlock = ^(ASDisplayNode *n, CGSize size){
calculateSizeCalled = YES;
passedInSize = size;
sizeCalculatedOnMainThread = [NSThread isMainThread];
return CGSizeZero;
};

dispatch_suspend([ASDisplayNode asyncSizingQueue]);

__block BOOL completed = NO;
ASDisplayNode *placeholder = [parent addSubnodeAsynchronously:nodeToAddAsync completion:^(ASDisplayNode *replacement) {
completed = YES;
}];

// Check it hasn't been added yet
XCTAssertTrue(placeholder.supernode == parent, @"didn't make a placeholder");
XCTAssertTrue(nodeToAddAsync.supernode == nil, @"oops, added node too soon");
XCTAssertFalse(calculateSizeCalled, @"too soon to calculate size!");

dispatch_resume([ASDisplayNode asyncSizingQueue]);

// Let the block execute on the bg thread
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return completed; }), @"Didn't finish the test fast enough");

XCTAssertTrue(placeholder.supernode == nil, @"didn't remove the placeholder");
XCTAssertTrue(nodeToAddAsync.supernode == parent, @"oops, didn't add the node");
XCTAssertTrue(calculateSizeCalled, @"too soon to calculate size!");
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(42, 56), passedInSize), @"Should pass in initial bounds size");
XCTAssertFalse(sizeCalculatedOnMainThread, @"Should pass in initial bounds size");

[parent release];
[nodeToAddAsync release];
}

- (void)testReplaceSubnodeAsync
{
ASTestDisplayNode *parent = [[ASTestDisplayNode alloc] init];

__block BOOL calculateSizeCalled = NO;
__block CGSize passedInSize;
__block BOOL sizeCalculatedOnMainThread;
ASTestDisplayNode *nodeToAddAsync = [[ASTestDisplayNode alloc] init];
nodeToAddAsync.bounds = CGRectMake(100, 40, 42, 56);
nodeToAddAsync.calculateSizeBlock = ^(ASDisplayNode *n, CGSize size){
calculateSizeCalled = YES;
passedInSize = size;
sizeCalculatedOnMainThread = [NSThread isMainThread];
return CGSizeZero;
};

ASDisplayNode *replaceMe = [[ASDisplayNode alloc] init];
[parent addSubnode:replaceMe];

dispatch_suspend([ASDisplayNode asyncSizingQueue]);

__block BOOL completed = NO;

[parent replaceSubnodeAsynchronously:replaceMe withNode:nodeToAddAsync completion:^(BOOL cancelled, ASDisplayNode *nodeToAddAsyncBlockArgument, ASDisplayNode *replaceMeBlockArgument) {
XCTAssertTrue(nodeToAddAsyncBlockArgument == nodeToAddAsync, @"Passed in wrong node for the replacing node");
XCTAssertTrue(replaceMeBlockArgument == replaceMe, @"Passed in wrong node for the replaced node");
completed = YES;
}];

// Check it hasn't been replaced yet
XCTAssertTrue(replaceMe.supernode == parent, @"removed too soon!");
XCTAssertTrue(nodeToAddAsync.supernode == nil, @"oops, added node too soon");
XCTAssertFalse(calculateSizeCalled, @"too soon to calculate size!");

dispatch_resume([ASDisplayNode asyncSizingQueue]);

// Let the block execute on the bg thread
XCTAssertTrue(ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return completed; }), @"Didn't finish the test fast enough");

XCTAssertTrue(replaceMe.supernode == nil, @"didn't remove old node");
XCTAssertTrue(nodeToAddAsync.supernode == parent, @"oops, added node too soon");
XCTAssertTrue(calculateSizeCalled, @"too soon to calculate size!");
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(42, 56), passedInSize), @"Should pass in initial bounds size");
XCTAssertFalse(sizeCalculatedOnMainThread, @"Should pass in initial bounds size");

[parent release];
[nodeToAddAsync release];
}

- (void)testCancelReplaceSubnodeAsyncByReplacingAgain
{

ASTestDisplayNode *parent = [[ASTestDisplayNode alloc] init];

dispatch_semaphore_t allowFirst = dispatch_semaphore_create(0);
ASTestDisplayNode *first = [[ASTestDisplayNode alloc] init];
first.bounds = CGRectMake(100, 40, 42, 56);
first.calculateSizeBlock = ^(ASDisplayNode *n, CGSize size){
dispatch_semaphore_wait(allowFirst, DISPATCH_TIME_FOREVER);
return CGSizeZero;
};

dispatch_semaphore_t allowSecond = dispatch_semaphore_create(0);
ASTestDisplayNode *second = [[ASTestDisplayNode alloc] init];
second.bounds = CGRectMake(100, 40, 42, 56);
second.calculateSizeBlock = ^(ASDisplayNode *n, CGSize size){
dispatch_semaphore_wait(allowSecond, DISPATCH_TIME_FOREVER);
return CGSizeMake(10, 20);
};


ASDisplayNode *replaceMe = [[ASDisplayNode alloc] init];
[parent addSubnode:replaceMe];

__block BOOL firstFinished = NO;
[parent replaceSubnodeAsynchronously:replaceMe withNode:first completion:^(BOOL cancelled, ASDisplayNode *firstBlockArgument, ASDisplayNode *replaceMeBlockArgument) {
XCTAssertNil(firstBlockArgument, @"Should have cancelled");
XCTAssertNil(replaceMeBlockArgument, @"Should have cancelled");
firstFinished = YES;
}];

__block BOOL secondFinished = NO;
[parent replaceSubnodeAsynchronously:replaceMe withNode:second completion:^(BOOL cancelled, ASDisplayNode *secondBlockArgument, ASDisplayNode *replaceMeBlockArgument) {
XCTAssertNotNil(secondBlockArgument, @"Should have the relevant node passed in");
XCTAssertNotNil(replaceMeBlockArgument, @"Should have the relevant node passed in");
secondFinished = YES;
}];

XCTAssertTrue(replaceMe.supernode == parent, @"didn't remove old node");
XCTAssertTrue(first.supernode == nil, @"oops, added node too soon");
XCTAssertTrue(second.supernode == nil, @"oops, added node too soon");
XCTAssertFalse(first.nodeLoaded, @"first view loaded too soon");
XCTAssertFalse(second.nodeLoaded, @"second view loaded too soon");

// Allow first to complete, but verify that the nodes are nil, indicating cancellation (asserts are in blocks above)
dispatch_semaphore_signal(allowFirst);

// Let the work execute on the bg thread
ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return firstFinished; });

XCTAssertTrue(first.supernode == nil, @"first should not be added to the hierarchy ever");
XCTAssertTrue(second.supernode == nil, @"second should not yet be added to the hierarchy");

dispatch_semaphore_signal(allowSecond);
ASDisplayNodeRunRunLoopUntilBlockIsTrue(^BOOL{ return secondFinished; });

XCTAssertTrue(first.supernode == nil, @"first should not be added to the hierarchy ever");
XCTAssertTrue(second.supernode == parent, @"second should be added now, woot!");
XCTAssertTrue(CGSizeEqualToSize(CGSizeMake(10, 20), [second calculatedSize]), @"Should have correct calculatedSize");

[parent release];
[first release];
[second release];
dispatch_release(allowFirst);
dispatch_release(allowSecond);
}

- (void)testInsertSubnodeAtIndexView
{
[self checkInsertSubnodeAtIndexWithViewLoaded:YES layerBacked:NO];
Expand Down

0 comments on commit af6c11a

Please sign in to comment.