diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e6001691..4c64e2d26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ## master * Add your own contributions to the next release on the line below this with your name. +- [ASDisplayNode.m] Make sure node is loaded before enter visible. [Max Wang](https://github.com/wsdwsd0829). [#886](https://github.com/TextureGroup/Texture/pull/886) - [ASTextNode2] Add improved support for all line-break modes in experimental text node. [Kevin Smith](https://github.com/wiseoldduck). [#1150](https://github.com/TextureGroup/Texture/pull/1150) - [ASExperimentalFeatures.m] Fix mismatch name in experimental features. [Max Wang](https://github.com/wsdwsd0829). [#1159](https://github.com/TextureGroup/Texture/pull/1159) - [ASCollectionViewLayoutController] Set default tuning parameters before view is loaded. [Max Wang](https://github.com/wsdwsd0829). [#1158](https://github.com/TextureGroup/Texture/pull/1158) diff --git a/Source/ASDisplayNode.mm b/Source/ASDisplayNode.mm index 7dd5c7d79..24adf9414 100644 --- a/Source/ASDisplayNode.mm +++ b/Source/ASDisplayNode.mm @@ -2265,7 +2265,14 @@ - (void)_insertSubnode:(ASDisplayNode *)subnode atSubnodeIndex:(NSInteger)subnod [_subnodes insertObject:subnode atIndex:subnodeIndex]; _cachedSubnodes = nil; __instanceLock__.unlock(); - + + if (!isRasterized && self.nodeLoaded) { + // Trigger the subnode to load its layer, which will create its view if it needs one. + // By doing this prior to downward propagation of .interfaceState in _setSupernode:, + // we can guarantee that -didEnterVisibleState is only called with .isNodeLoaded = YES. + [subnode layer]; + } + // This call will apply our .hierarchyState to the new subnode. // If we are a managed hierarchy, as in ASCellNode trees, it will also apply our .interfaceState. [subnode _setSupernode:self]; @@ -3272,10 +3279,17 @@ - (void)didEnterVisibleState { // subclass override ASDisplayNodeAssertMainThread(); + + // Rasterized node's loading state is merged with root node of rasterized tree. + if (!(self.hierarchyState & ASHierarchyStateRasterized)) { + ASDisplayNodeAssert(self.isNodeLoaded, @"Node should be loaded before entering visible state."); + } + ASAssertUnlocked(__instanceLock__); [self enumerateInterfaceStateDelegates:^(id del) { [del didEnterVisibleState]; }]; + #if AS_ENABLE_TIPS [ASTipsController.shared nodeDidAppear:self]; #endif diff --git a/Tests/ASNetworkImageNodeTests.m b/Tests/ASNetworkImageNodeTests.m index 1dcc363e0..20026a995 100644 --- a/Tests/ASNetworkImageNodeTests.m +++ b/Tests/ASNetworkImageNodeTests.m @@ -57,6 +57,7 @@ - (void)DISABLED_testThatProgressBlockIsSetAndClearedCorrectlyOnVisibility - (void)testThatProgressBlockIsSetAndClearedCorrectlyOnChangeURL { + [node layer]; [node enterInterfaceState:ASInterfaceStateInHierarchy]; // Set URL while visible, should set progress block diff --git a/Tests/ASVideoNodeTests.m b/Tests/ASVideoNodeTests.m index 6a4311cfc..727d5666b 100644 --- a/Tests/ASVideoNodeTests.m +++ b/Tests/ASVideoNodeTests.m @@ -199,9 +199,9 @@ - (void)testPlayerLayerNodeIsNotAddedIfVisibleButShouldNotBePlayingWithUrl - (void)doPlayerLayerNodeIsNotAddedIfVisibleButShouldNotBePlaying { [_videoNode pause]; + [_videoNode layer]; [_videoNode setInterfaceState:ASInterfaceStateVisible | ASInterfaceStateDisplay]; - [_videoNode didLoad]; - + XCTAssert(![_videoNode.subnodes containsObject:_videoNode.playerNode]); } @@ -226,7 +226,8 @@ - (void)doVideoStartsPlayingOnDidDidBecomeVisibleWhenShouldAutoplay return playerLayer; }]; _videoNode.playerNode.layer.frame = CGRectZero; - + + [_videoNode layer]; [_videoNode didEnterVisibleState]; XCTAssertTrue(_videoNode.shouldBePlaying); @@ -304,7 +305,7 @@ - (void)testVideoThatDoesNotAutorepeatsShouldPauseOnPlaybackEnd _videoNode.asset = assetMock; _videoNode.shouldAutorepeat = NO; - [_videoNode didLoad]; + [_videoNode layer]; [_videoNode setInterfaceState:ASInterfaceStateVisible | ASInterfaceStateDisplay | ASInterfaceStatePreload]; [_videoNode prepareToPlayAsset:assetMock withKeys:_requestedKeys]; [_videoNode play]; @@ -325,7 +326,7 @@ - (void)testVideoThatAutorepeatsShouldRepeatOnPlaybackEnd _videoNode.asset = assetMock; _videoNode.shouldAutorepeat = YES; - [_videoNode didLoad]; + [_videoNode layer]; [_videoNode setInterfaceState:ASInterfaceStateVisible | ASInterfaceStateDisplay | ASInterfaceStatePreload]; [_videoNode prepareToPlayAsset:assetMock withKeys:_requestedKeys]; [_videoNode play]; @@ -342,6 +343,7 @@ - (void)testVideoResumedWhenBufferIsLikelyToKeepUp _videoNode.asset = assetMock; + [_videoNode layer]; [_videoNode setInterfaceState:ASInterfaceStateVisible | ASInterfaceStateDisplay | ASInterfaceStatePreload]; [_videoNode prepareToPlayAsset:assetMock withKeys:_requestedKeys]; ASCATransactionQueueWait(nil);