mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Introduced ASHierarchyState. Created ASDisplayNode+FrameworkPrivate.h. Fixed deadlock.
This commit is contained in:
@@ -441,6 +441,8 @@
|
|||||||
D785F6621A74327E00291744 /* ASScrollNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D785F6601A74327E00291744 /* ASScrollNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
D785F6621A74327E00291744 /* ASScrollNode.h in Headers */ = {isa = PBXBuildFile; fileRef = D785F6601A74327E00291744 /* ASScrollNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */ = {isa = PBXBuildFile; fileRef = D785F6611A74327E00291744 /* ASScrollNode.m */; };
|
||||||
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
|
DB7121BCD50849C498C886FB /* libPods-AsyncDisplayKitTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */; };
|
||||||
|
DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
||||||
|
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */; };
|
||||||
DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
DECBD6E71BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
DECBD6E81BE56E1900CF4905 /* ASButtonNode.h in Headers */ = {isa = PBXBuildFile; fileRef = DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
DECBD6E91BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||||
@@ -725,6 +727,7 @@
|
|||||||
D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
D3779BCFF841AD3EB56537ED /* Pods-AsyncDisplayKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
D785F6601A74327E00291744 /* ASScrollNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASScrollNode.h; sourceTree = "<group>"; };
|
||||||
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
D785F6611A74327E00291744 /* ASScrollNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASScrollNode.m; sourceTree = "<group>"; };
|
||||||
|
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ASDisplayNode+FrameworkPrivate.h"; sourceTree = "<group>"; };
|
||||||
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = "<group>"; };
|
DECBD6E51BE56E1900CF4905 /* ASButtonNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASButtonNode.h; sourceTree = "<group>"; };
|
||||||
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
|
DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASButtonNode.mm; sourceTree = "<group>"; };
|
||||||
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
EFA731F0396842FF8AB635EE /* libPods-AsyncDisplayKitTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-AsyncDisplayKitTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -1045,6 +1048,7 @@
|
|||||||
058D0A09195D050800B7D73C /* ASDisplayNode+DebugTiming.h */,
|
058D0A09195D050800B7D73C /* ASDisplayNode+DebugTiming.h */,
|
||||||
058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */,
|
058D0A0A195D050800B7D73C /* ASDisplayNode+DebugTiming.mm */,
|
||||||
058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */,
|
058D0A0B195D050800B7D73C /* ASDisplayNode+UIViewBridge.mm */,
|
||||||
|
DE6EA3211C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h */,
|
||||||
058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */,
|
058D0A0C195D050800B7D73C /* ASDisplayNodeInternal.h */,
|
||||||
058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */,
|
058D0A0D195D050800B7D73C /* ASImageNode+CGExtras.h */,
|
||||||
058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */,
|
058D0A0E195D050800B7D73C /* ASImageNode+CGExtras.m */,
|
||||||
@@ -1231,6 +1235,7 @@
|
|||||||
257754B11BEE44CD00737CA5 /* ASTextKitShadower.h in Headers */,
|
257754B11BEE44CD00737CA5 /* ASTextKitShadower.h in Headers */,
|
||||||
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
|
058D0A7B195D05F900B7D73C /* ASDisplayNodeInternal.h in Headers */,
|
||||||
0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */,
|
0587F9BD1A7309ED00AFF0BA /* ASEditableTextNode.h in Headers */,
|
||||||
|
DE6EA3221C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */,
|
||||||
1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */,
|
1950C4491A3BB5C1005C8279 /* ASEqualityHelpers.h in Headers */,
|
||||||
257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */,
|
257754A81BEE44CD00737CA5 /* ASTextKitContext.h in Headers */,
|
||||||
464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */,
|
464052221A3F83C40061C0BA /* ASFlowLayoutController.h in Headers */,
|
||||||
@@ -1340,6 +1345,7 @@
|
|||||||
254C6B791BF94DF4003EC431 /* ASTextKitEntityAttribute.h in Headers */,
|
254C6B791BF94DF4003EC431 /* ASTextKitEntityAttribute.h in Headers */,
|
||||||
509E68631B3AEDB4009B9150 /* ASCollectionViewLayoutController.h in Headers */,
|
509E68631B3AEDB4009B9150 /* ASCollectionViewLayoutController.h in Headers */,
|
||||||
B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */,
|
B35061F71B010EFD0018CF92 /* ASCollectionViewProtocols.h in Headers */,
|
||||||
|
DE6EA3231C14000600183B10 /* ASDisplayNode+FrameworkPrivate.h in Headers */,
|
||||||
B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */,
|
B35061FA1B010EFD0018CF92 /* ASControlNode+Subclasses.h in Headers */,
|
||||||
B35061F81B010EFD0018CF92 /* ASControlNode.h in Headers */,
|
B35061F81B010EFD0018CF92 /* ASControlNode.h in Headers */,
|
||||||
B35062171B010EFD0018CF92 /* ASDataController.h in Headers */,
|
B35062171B010EFD0018CF92 /* ASDataController.h in Headers */,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
if (!(self = [super init]))
|
if (!(self = [super init]))
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// use UITableViewCell defaults
|
// Use UITableViewCell defaults
|
||||||
_selectionStyle = UITableViewCellSelectionStyleDefault;
|
_selectionStyle = UITableViewCellSelectionStyleDefault;
|
||||||
self.clipsToBounds = YES;
|
self.clipsToBounds = YES;
|
||||||
|
|
||||||
|
|||||||
@@ -6,19 +6,16 @@
|
|||||||
* of patent rights can be found in the PATENTS file in the same directory.
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#import "ASCollectionView.h"
|
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASCollectionViewLayoutController.h"
|
|
||||||
#import "ASRangeController.h"
|
|
||||||
#import "ASCollectionDataController.h"
|
|
||||||
#import "ASBatchFetching.h"
|
#import "ASBatchFetching.h"
|
||||||
#import "UICollectionViewLayout+ASConvenience.h"
|
#import "ASCollectionView.h"
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASCollectionDataController.h"
|
||||||
|
#import "ASCollectionViewLayoutController.h"
|
||||||
#import "ASCollectionViewFlowLayoutInspector.h"
|
#import "ASCollectionViewFlowLayoutInspector.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASRangeController.h"
|
||||||
|
#import "UICollectionViewLayout+ASConvenience.h"
|
||||||
|
|
||||||
static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone;
|
static const NSUInteger kASCollectionViewAnimationNone = UITableViewRowAnimationNone;
|
||||||
static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero};
|
static const ASSizeRange kInvalidSizeRange = {CGSizeZero, CGSizeZero};
|
||||||
@@ -661,6 +658,8 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
ASCellNode *node = [_asyncDataSource collectionView:self nodeForItemAtIndexPath:indexPath];
|
ASCellNode *node = [_asyncDataSource collectionView:self nodeForItemAtIndexPath:indexPath];
|
||||||
|
[node enterHierarchyState:ASHierarchyStateRangeManaged];
|
||||||
|
|
||||||
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
||||||
if (node.layoutDelegate == nil) {
|
if (node.layoutDelegate == nil) {
|
||||||
node.layoutDelegate = self;
|
node.layoutDelegate = self;
|
||||||
|
|||||||
@@ -412,10 +412,8 @@
|
|||||||
*/
|
*/
|
||||||
- (UIImage *)placeholderImage;
|
- (UIImage *)placeholderImage;
|
||||||
|
|
||||||
|
|
||||||
/** @name Description */
|
/** @name Description */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @abstract Return a description of the node
|
* @abstract Return a description of the node
|
||||||
*
|
*
|
||||||
@@ -425,47 +423,5 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@interface ASDisplayNode (ASDisplayNodePrivate)
|
|
||||||
/**
|
|
||||||
* This method has proven helpful in a few rare scenarios, similar to a category extension on UIView,
|
|
||||||
* but it's considered private API for now and its use should not be encouraged.
|
|
||||||
* @param checkViewHierarchy If YES, and no supernode can be found, method will walk up from `self.view` to find a supernode.
|
|
||||||
* If YES, this method must be called on the main thread and the node must not be layer-backed.
|
|
||||||
*/
|
|
||||||
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy;
|
|
||||||
|
|
||||||
// The two methods below will eventually be exposed, but their names are subject to change.
|
|
||||||
/**
|
|
||||||
* @abstract Ensure that all rendering is complete for this node and its descendents.
|
|
||||||
*
|
|
||||||
* @discussion Calling this method on the main thread after a node is added to the view heirarchy will ensure that
|
|
||||||
* placeholder states are never visible to the user. It is used by ASTableView, ASCollectionView, and ASViewController
|
|
||||||
* to implement their respective ".neverShowPlaceholders" option.
|
|
||||||
*
|
|
||||||
* If all nodes have layer.contents set and/or their layer does not have -needsDisplay set, the method will return immediately.
|
|
||||||
*
|
|
||||||
* This method is capable of handling a mixed set of nodes, with some not having started display, some in progress on an
|
|
||||||
* asynchronous display operation, and some already finished.
|
|
||||||
*
|
|
||||||
* In order to guarantee against deadlocks, this method should only be called on the main thread.
|
|
||||||
* It may block on the private queue, [_ASDisplayLayer displayQueue]
|
|
||||||
*/
|
|
||||||
- (void)recursivelyEnsureDisplay;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @abstract Allows a node to bypass all ensureDisplay passes. Defaults to NO.
|
|
||||||
*
|
|
||||||
* @discussion Nodes that are expensive to draw and expected to have placeholder even with
|
|
||||||
* .neverShowPlaceholders enabled should set this to YES.
|
|
||||||
*
|
|
||||||
* ASImageNode uses the default of NO, as it is often used for UI images that are expected to synchronize with ensureDisplay.
|
|
||||||
*
|
|
||||||
* ASNetworkImageNode and ASMultiplexImageNode set this to YES, because they load data from a database or server,
|
|
||||||
* and are expected to support a placeholder state given that display is often blocked on slow data fetching.
|
|
||||||
*/
|
|
||||||
@property (nonatomic, assign) BOOL shouldBypassEnsureDisplay;
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#define ASDisplayNodeAssertThreadAffinity(viewNode) ASDisplayNodeAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity - this method should not be called off the main thread after the ASDisplayNode's view or layer have been created")
|
#define ASDisplayNodeAssertThreadAffinity(viewNode) ASDisplayNodeAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity - this method should not be called off the main thread after the ASDisplayNode's view or layer have been created")
|
||||||
#define ASDisplayNodeCAssertThreadAffinity(viewNode) ASDisplayNodeCAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity - this method should not be called off the main thread after the ASDisplayNode's view or layer have been created")
|
#define ASDisplayNodeCAssertThreadAffinity(viewNode) ASDisplayNodeCAssert(!viewNode || ASDisplayNodeThreadIsMain() || !(viewNode).nodeLoaded, @"Incorrect display node thread affinity - this method should not be called off the main thread after the ASDisplayNode's view or layer have been created")
|
||||||
|
|||||||
@@ -7,8 +7,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "ASDisplayNode.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASLayoutOptionsPrivate.h"
|
#import "ASLayoutOptionsPrivate.h"
|
||||||
|
|
||||||
#import <objc/runtime.h>
|
#import <objc/runtime.h>
|
||||||
@@ -38,6 +39,9 @@
|
|||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||||
|
#define LOG(...)
|
||||||
|
|
||||||
// Conditionally time these scopes to our debug ivars (only exist in debug/profile builds)
|
// Conditionally time these scopes to our debug ivars (only exist in debug/profile builds)
|
||||||
#if TIME_DISPLAYNODE_OPS
|
#if TIME_DISPLAYNODE_OPS
|
||||||
#define TIME_SCOPED(outVar) ASDN::ScopeTimer t(outVar)
|
#define TIME_SCOPED(outVar) ASDN::ScopeTimer t(outVar)
|
||||||
@@ -323,17 +327,6 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
|
|
||||||
#pragma mark - Core
|
#pragma mark - Core
|
||||||
|
|
||||||
- (void)__tearDown:(BOOL)tearDown subnodesOfNode:(ASDisplayNode *)node
|
|
||||||
{
|
|
||||||
for (ASDisplayNode *subnode in node.subnodes) {
|
|
||||||
if (tearDown) {
|
|
||||||
[subnode __unloadNode];
|
|
||||||
} else {
|
|
||||||
[subnode __loadNode];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)__unloadNode
|
- (void)__unloadNode
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertThreadAffinity(self);
|
ASDisplayNodeAssertThreadAffinity(self);
|
||||||
@@ -357,22 +350,9 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
[self layer];
|
[self layer];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (ASDisplayNode *)__rasterizedContainerNode
|
|
||||||
{
|
|
||||||
ASDisplayNode *node = self.supernode;
|
|
||||||
while (node) {
|
|
||||||
if (node.shouldRasterizeDescendants) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
node = node.supernode;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (BOOL)__shouldLoadViewOrLayer
|
- (BOOL)__shouldLoadViewOrLayer
|
||||||
{
|
{
|
||||||
return ![self __rasterizedContainerNode];
|
return !(_hierarchyState & ASHierarchyStateRasterized);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)__shouldSize
|
- (BOOL)__shouldSize
|
||||||
@@ -645,30 +625,44 @@ static ASDisplayNodeMethodOverrides GetASDisplayNodeMethodOverrides(Class c)
|
|||||||
{
|
{
|
||||||
ASDisplayNodeAssertThreadAffinity(self);
|
ASDisplayNodeAssertThreadAffinity(self);
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
ASDisplayNodeAssert(!((_hierarchyState & ASHierarchyStateRasterized) && _flags.shouldRasterizeDescendants),
|
||||||
|
@"Subnode of a rasterized node should not have redundant shouldRasterizeDescendants enabled");
|
||||||
return _flags.shouldRasterizeDescendants;
|
return _flags.shouldRasterizeDescendants;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setShouldRasterizeDescendants:(BOOL)flag
|
- (void)setShouldRasterizeDescendants:(BOOL)shouldRasterize
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertThreadAffinity(self);
|
ASDisplayNodeAssertThreadAffinity(self);
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
|
||||||
if (_flags.shouldRasterizeDescendants == flag)
|
if (_flags.shouldRasterizeDescendants == shouldRasterize)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_flags.shouldRasterizeDescendants = flag;
|
_flags.shouldRasterizeDescendants = shouldRasterize;
|
||||||
|
|
||||||
if (self.isNodeLoaded) {
|
if (self.isNodeLoaded) {
|
||||||
//recursively tear down or build up subnodes
|
// Recursively tear down or build up subnodes.
|
||||||
|
// TODO: When disabling rasterization, preserve rasterized backing store as placeholderImage
|
||||||
|
// while the newly materialized subtree finishes rendering. Then destroy placeholderImage to save memory.
|
||||||
[self recursivelyClearContents];
|
[self recursivelyClearContents];
|
||||||
[self __tearDown:flag subnodesOfNode:self];
|
|
||||||
if (flag == NO) {
|
|
||||||
[self _addSubnodeViewsAndLayers];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ASDisplayNodePerformBlockOnEverySubnode(self, ^(ASDisplayNode *node) {
|
||||||
|
if (shouldRasterize) {
|
||||||
|
[node enterHierarchyState:ASHierarchyStateRasterized];
|
||||||
|
[node __unloadNode];
|
||||||
|
} else {
|
||||||
|
[node exitHierarchyState:ASHierarchyStateRasterized];
|
||||||
|
[node __loadNode];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (self.interfaceState & ASInterfaceStateVisible) {
|
||||||
|
// TODO: Change this to recursivelyEnsureDisplay - but need a variant that does not skip
|
||||||
|
// nodes that have shouldBypassEnsureDisplay set (such as image nodes) so they are rasterized.
|
||||||
[self recursivelyDisplayImmediately];
|
[self recursivelyDisplayImmediately];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (CGFloat)contentsScaleForDisplay
|
- (CGFloat)contentsScaleForDisplay
|
||||||
{
|
{
|
||||||
@@ -969,7 +963,7 @@ static bool disableNotificationsForMovingBetweenParents(ASDisplayNode *from, ASD
|
|||||||
[_subnodes insertObject:subnode atIndex:subnodeIndex];
|
[_subnodes insertObject:subnode atIndex:subnodeIndex];
|
||||||
|
|
||||||
// Don't bother inserting the view/layer if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work.
|
// Don't bother inserting the view/layer if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work.
|
||||||
if (!_flags.shouldRasterizeDescendants && ![self __rasterizedContainerNode]) {
|
if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) {
|
||||||
if (_layer) {
|
if (_layer) {
|
||||||
ASDisplayNodeCAssertMainThread();
|
ASDisplayNodeCAssertMainThread();
|
||||||
|
|
||||||
@@ -1090,7 +1084,7 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
NSInteger aboveSublayerIndex = NSNotFound;
|
NSInteger aboveSublayerIndex = NSNotFound;
|
||||||
|
|
||||||
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work.
|
// Don't bother figuring out the sublayerIndex if in a rasterized subtree, becuase there are no layers in the hierarchy and none of this could possibly work.
|
||||||
if (!_flags.shouldRasterizeDescendants && ![self __rasterizedContainerNode]) {
|
if (!_flags.shouldRasterizeDescendants && [self __shouldLoadViewOrLayer]) {
|
||||||
if (_layer) {
|
if (_layer) {
|
||||||
aboveSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:above.layer];
|
aboveSublayerIndex = [_layer.sublayers indexOfObjectIdenticalTo:above.layer];
|
||||||
ASDisplayNodeAssert(aboveSublayerIndex != NSNotFound, @"Somehow above's supernode is self, yet we could not find it in our layers to replace");
|
ASDisplayNodeAssert(aboveSublayerIndex != NSNotFound, @"Somehow above's supernode is self, yet we could not find it in our layers to replace");
|
||||||
@@ -1345,7 +1339,15 @@ static NSInteger incrementIfFound(NSInteger i) {
|
|||||||
- (void)__setSupernode:(ASDisplayNode *)supernode
|
- (void)__setSupernode:(ASDisplayNode *)supernode
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
if (_supernode != supernode) {
|
||||||
|
ASHierarchyState oldHierarchyState = _supernode.hierarchyState;
|
||||||
_supernode = supernode;
|
_supernode = supernode;
|
||||||
|
if (_supernode) {
|
||||||
|
[self enterHierarchyState:_supernode.hierarchyState];
|
||||||
|
} else {
|
||||||
|
[self exitHierarchyState:oldHierarchyState];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track that a node will be displayed as part of the current node hierarchy.
|
// Track that a node will be displayed as part of the current node hierarchy.
|
||||||
@@ -1653,7 +1655,8 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
* @see https://github.com/facebook/AsyncDisplayKit/issues/900
|
* @see https://github.com/facebook/AsyncDisplayKit/issues/900
|
||||||
* Possible solution is to push `isInCellNode` state downward on `addSubnode`/`removeFromSupernode`.
|
* Possible solution is to push `isInCellNode` state downward on `addSubnode`/`removeFromSupernode`.
|
||||||
*/
|
*/
|
||||||
- (BOOL)supportsInterfaceState {
|
- (BOOL)supportsInterfaceState
|
||||||
|
{
|
||||||
return ([self isKindOfClass:ASCellNode.class]
|
return ([self isKindOfClass:ASCellNode.class]
|
||||||
|| [self _supernodeWithClass:ASCellNode.class checkViewHierarchy:NO] != nil);
|
|| [self _supernodeWithClass:ASCellNode.class checkViewHierarchy:NO] != nil);
|
||||||
}
|
}
|
||||||
@@ -1664,23 +1667,23 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
return _interfaceState;
|
return _interfaceState;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setInterfaceState:(ASInterfaceState)interfaceState
|
- (void)setInterfaceState:(ASInterfaceState)newState
|
||||||
{
|
{
|
||||||
ASInterfaceState oldValue;
|
ASInterfaceState oldState;
|
||||||
{
|
{
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
oldValue = _interfaceState;
|
oldState = _interfaceState;
|
||||||
_interfaceState = interfaceState;
|
_interfaceState = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interfaceState != oldValue) {
|
if (newState != oldState) {
|
||||||
if ((interfaceState & ASInterfaceStateMeasureLayout) != (oldValue & ASInterfaceStateMeasureLayout)) {
|
if ((newState & ASInterfaceStateMeasureLayout) != (oldState & ASInterfaceStateMeasureLayout)) {
|
||||||
// Trigger asynchronous measurement if it is not already cached or being calculated.
|
// Trigger asynchronous measurement if it is not already cached or being calculated.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Entered or exited data loading state.
|
// Entered or exited data loading state.
|
||||||
if ((interfaceState & ASInterfaceStateFetchData) != (oldValue & ASInterfaceStateFetchData)) {
|
if ((newState & ASInterfaceStateFetchData) != (oldState & ASInterfaceStateFetchData)) {
|
||||||
if (interfaceState & ASInterfaceStateFetchData) {
|
if (newState & ASInterfaceStateFetchData) {
|
||||||
[self fetchData];
|
[self fetchData];
|
||||||
} else {
|
} else {
|
||||||
[self clearFetchedData];
|
[self clearFetchedData];
|
||||||
@@ -1688,8 +1691,8 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Entered or exited contents rendering state.
|
// Entered or exited contents rendering state.
|
||||||
if ((interfaceState & ASInterfaceStateDisplay) != (oldValue & ASInterfaceStateDisplay)) {
|
if ((newState & ASInterfaceStateDisplay) != (oldState & ASInterfaceStateDisplay)) {
|
||||||
if (interfaceState & ASInterfaceStateDisplay) {
|
if (newState & ASInterfaceStateDisplay) {
|
||||||
// Once the working window is eliminated (ASRangeHandlerRender), trigger display directly here.
|
// Once the working window is eliminated (ASRangeHandlerRender), trigger display directly here.
|
||||||
[self setDisplaySuspended:NO];
|
[self setDisplaySuspended:NO];
|
||||||
} else {
|
} else {
|
||||||
@@ -1699,14 +1702,13 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Entered or exited data loading state.
|
// Entered or exited data loading state.
|
||||||
if ((interfaceState & ASInterfaceStateVisible) != (oldValue & ASInterfaceStateVisible)) {
|
if ((newState & ASInterfaceStateVisible) != (oldState & ASInterfaceStateVisible)) {
|
||||||
if (interfaceState & ASInterfaceStateVisible) {
|
if (newState & ASInterfaceStateVisible) {
|
||||||
// Consider providing a -didBecomeVisible.
|
// Consider providing a -didBecomeVisible.
|
||||||
} else {
|
} else {
|
||||||
// Consider providing a -didBecomeInvisible.
|
// Consider providing a -didBecomeInvisible.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1724,6 +1726,40 @@ void recursivelyEnsureDisplayForLayer(CALayer *layer)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (ASHierarchyState)hierarchyState
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
return _hierarchyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setHierarchyState:(ASHierarchyState)newState
|
||||||
|
{
|
||||||
|
ASHierarchyState oldState;
|
||||||
|
{
|
||||||
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
oldState = _hierarchyState;
|
||||||
|
_hierarchyState = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newState != oldState) {
|
||||||
|
LOG(@"setHierarchyState: oldState = %lu, newState = %lu", (unsigned long)oldState, (unsigned long)newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)enterHierarchyState:(ASHierarchyState)hierarchyState
|
||||||
|
{
|
||||||
|
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||||
|
node.hierarchyState |= hierarchyState;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)exitHierarchyState:(ASHierarchyState)hierarchyState
|
||||||
|
{
|
||||||
|
ASDisplayNodePerformBlockOnEveryNode(nil, self, ^(ASDisplayNode *node) {
|
||||||
|
node.hierarchyState &= (~hierarchyState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
- (void)layout
|
- (void)layout
|
||||||
{
|
{
|
||||||
ASDisplayNodeAssertMainThread();
|
ASDisplayNodeAssertMainThread();
|
||||||
|
|||||||
@@ -37,6 +37,12 @@ extern ASDisplayNode *ASDisplayNodeUltimateParentOfNode(ASDisplayNode *node);
|
|||||||
*/
|
*/
|
||||||
extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node));
|
extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *node, void(^block)(ASDisplayNode *node));
|
||||||
|
|
||||||
|
/**
|
||||||
|
Identical to ASDisplayNodePerformBlockOnEveryNode, except it does not run the block on the
|
||||||
|
node provided directly to the function call - only on all descendants.
|
||||||
|
*/
|
||||||
|
extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, void(^block)(ASDisplayNode *node));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block.
|
Given a display node, traverses up the layer tree hierarchy, returning the first display node that passes block.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -7,8 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
|
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer)
|
extern ASDisplayNode *ASLayerToDisplayNode(CALayer *layer)
|
||||||
{
|
{
|
||||||
@@ -46,6 +46,13 @@ extern void ASDisplayNodePerformBlockOnEveryNode(CALayer *layer, ASDisplayNode *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern void ASDisplayNodePerformBlockOnEverySubnode(ASDisplayNode *node, void(^block)(ASDisplayNode *node))
|
||||||
|
{
|
||||||
|
for (ASDisplayNode *subnode in node.subnodes) {
|
||||||
|
ASDisplayNodePerformBlockOnEveryNode(nil, subnode, block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node))
|
id ASDisplayNodeFind(ASDisplayNode *node, BOOL (^block)(ASDisplayNode *node))
|
||||||
{
|
{
|
||||||
CALayer *layer = node.layer;
|
CALayer *layer = node.layer;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#import "ASAvailability.h"
|
#import "ASAvailability.h"
|
||||||
#import "ASBaseDefines.h"
|
#import "ASBaseDefines.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASLog.h"
|
#import "ASLog.h"
|
||||||
#import "ASPhotosFrameworkImageRequest.h"
|
#import "ASPhotosFrameworkImageRequest.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
|
|||||||
@@ -10,8 +10,9 @@
|
|||||||
|
|
||||||
#import "ASBasicImageDownloader.h"
|
#import "ASBasicImageDownloader.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASThread.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
|
#import "ASThread.h"
|
||||||
|
|
||||||
@interface ASNetworkImageNode ()
|
@interface ASNetworkImageNode ()
|
||||||
{
|
{
|
||||||
@@ -30,10 +31,8 @@
|
|||||||
|
|
||||||
BOOL _imageLoaded;
|
BOOL _imageLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|
||||||
@implementation ASNetworkImageNode
|
@implementation ASNetworkImageNode
|
||||||
|
|
||||||
- (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASImageDownloaderProtocol>)downloader
|
- (instancetype)initWithCache:(id<ASImageCacheProtocol>)cache downloader:(id<ASImageDownloaderProtocol>)downloader
|
||||||
|
|||||||
@@ -10,16 +10,14 @@
|
|||||||
#import "ASTableViewInternal.h"
|
#import "ASTableViewInternal.h"
|
||||||
|
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
|
#import "ASBatchFetching.h"
|
||||||
#import "ASChangeSetDataController.h"
|
#import "ASChangeSetDataController.h"
|
||||||
#import "ASCollectionViewLayoutController.h"
|
#import "ASCollectionViewLayoutController.h"
|
||||||
#import "ASLayoutController.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASRangeController.h"
|
|
||||||
#import "ASBatchFetching.h"
|
|
||||||
#import "ASInternalHelpers.h"
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASLayout.h"
|
#import "ASLayout.h"
|
||||||
|
#import "ASLayoutController.h"
|
||||||
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
#import "ASRangeController.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
|
||||||
|
|
||||||
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||||
|
|
||||||
@@ -829,6 +827,8 @@ static BOOL _isInterceptedSelector(SEL sel)
|
|||||||
- (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath
|
- (ASCellNode *)dataController:(ASDataController *)dataController nodeAtIndexPath:(NSIndexPath *)indexPath
|
||||||
{
|
{
|
||||||
ASCellNode *node = [_asyncDataSource tableView:self nodeForRowAtIndexPath:indexPath];
|
ASCellNode *node = [_asyncDataSource tableView:self nodeForRowAtIndexPath:indexPath];
|
||||||
|
[node enterHierarchyState:ASHierarchyStateRangeManaged];
|
||||||
|
|
||||||
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
ASDisplayNodeAssert([node isKindOfClass:ASCellNode.class], @"invalid node class, expected ASCellNode");
|
||||||
if (node.layoutDelegate == nil) {
|
if (node.layoutDelegate == nil) {
|
||||||
node.layoutDelegate = self;
|
node.layoutDelegate = self;
|
||||||
|
|||||||
@@ -9,9 +9,7 @@
|
|||||||
#import "ASViewController.h"
|
#import "ASViewController.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDimension.h"
|
#import "ASDimension.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
// FIXME: Temporary nonsense import until method names are finalized and exposed
|
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
|
||||||
|
|
||||||
@implementation ASViewController
|
@implementation ASViewController
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#import "ASRangeHandlerPreload.h"
|
#import "ASRangeHandlerPreload.h"
|
||||||
#import "ASDisplayNode.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
@implementation ASRangeHandlerPreload
|
@implementation ASRangeHandlerPreload
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#import "ASDisplayNode.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
@interface ASRangeHandlerRender ()
|
@interface ASRangeHandlerRender ()
|
||||||
@property (nonatomic,readonly) UIWindow *workingWindow;
|
@property (nonatomic,readonly) UIWindow *workingWindow;
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#import "ASRangeHandlerVisible.h"
|
#import "ASRangeHandlerVisible.h"
|
||||||
#import "ASDisplayNode.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
@implementation ASRangeHandlerVisible
|
@implementation ASRangeHandlerVisible
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNode.h"
|
#import "ASDisplayNode.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
@implementation _ASDisplayLayer
|
@implementation _ASDisplayLayer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNodeExtras.h"
|
#import "ASDisplayNodeExtras.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
|
||||||
@interface _ASDisplayView ()
|
@interface _ASDisplayView ()
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#import "_ASAsyncTransaction.h"
|
#import "_ASAsyncTransaction.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
|
|
||||||
@implementation ASDisplayNode (AsyncDisplay)
|
@implementation ASDisplayNode (AsyncDisplay)
|
||||||
|
|
||||||
@@ -84,7 +85,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL rasterizingFromAscendent = [self __rasterizedContainerNode] != nil;
|
BOOL rasterizingFromAscendent = (_hierarchyState & ASHierarchyStateRasterized);
|
||||||
|
|
||||||
// if super node is rasterizing descendents, subnodes will not have had layout calls becase they don't have layers
|
// if super node is rasterizing descendents, subnodes will not have had layout calls becase they don't have layers
|
||||||
if (rasterizingFromAscendent) {
|
if (rasterizingFromAscendent) {
|
||||||
@@ -178,7 +179,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
|
|
||||||
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil;
|
asyncdisplaykit_async_transaction_operation_block_t displayBlock = nil;
|
||||||
|
|
||||||
ASDisplayNodeAssert(rasterizing || ![self __rasterizedContainerNode], @"Rasterized descendants should never display unless being drawn into the rasterized container.");
|
ASDisplayNodeAssert(rasterizing || !(_hierarchyState & ASHierarchyStateRasterized), @"Rasterized descendants should never display unless being drawn into the rasterized container.");
|
||||||
|
|
||||||
if (!rasterizing && self.shouldRasterizeDescendants) {
|
if (!rasterizing && self.shouldRasterizeDescendants) {
|
||||||
CGRect bounds = self.bounds;
|
CGRect bounds = self.bounds;
|
||||||
@@ -296,7 +297,7 @@ static void __ASDisplayLayerDecrementConcurrentDisplayCount(BOOL displayIsAsync,
|
|||||||
|
|
||||||
ASDN::MutexLocker l(_propertyLock);
|
ASDN::MutexLocker l(_propertyLock);
|
||||||
|
|
||||||
if ([self __rasterizedContainerNode]) {
|
if (_hierarchyState & ASHierarchyStateRasterized) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
109
AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h
Normal file
109
AsyncDisplayKit/Private/ASDisplayNode+FrameworkPrivate.h
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
/* Copyright (c) 2014-present, Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD-style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// The following methods are ONLY for use by _ASDisplayLayer, _ASDisplayView, and ASDisplayNode.
|
||||||
|
// These methods must never be called or overridden by other classes.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "_ASDisplayLayer.h"
|
||||||
|
#import "_AS-objc-internal.h"
|
||||||
|
#import "ASDisplayNodeExtraIvars.h"
|
||||||
|
#import "ASDisplayNode.h"
|
||||||
|
#import "ASSentinel.h"
|
||||||
|
#import "ASThread.h"
|
||||||
|
#import "ASLayoutOptions.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
Hierarchy state is propogated from nodes to all of their children when certain behaviors are required from the subtree.
|
||||||
|
Examples include rasterization and external driving of the .interfaceState property.
|
||||||
|
By passing this information explicitly, performance is optimized by avoiding iteration up the supernode chain.
|
||||||
|
Lastly, this avoidance of supernode traversal protects against the possibility of deadlocks when a supernode is
|
||||||
|
simultaneously attempting to materialize views / layers for its subtree (as many related methods require property locking)
|
||||||
|
|
||||||
|
Note: as the hierarchy deepens, more state properties may be enabled. However, state properties may never be disabled /
|
||||||
|
cancelled below the point they are enabled. They continue to the leaves of the hierarchy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef NS_OPTIONS(NSUInteger, ASHierarchyState)
|
||||||
|
{
|
||||||
|
/** The node may or may not have a supernode, but no supernode has a special hierarchy-influencing option enabled. */
|
||||||
|
ASHierarchyStateNormal = 0,
|
||||||
|
/** The node has a supernode with .shouldRasterizeDescendants = YES.
|
||||||
|
Note: the root node of the rasterized subtree (the one with the property set on it) will NOT have this state set. */
|
||||||
|
ASHierarchyStateRasterized = 1 << 0,
|
||||||
|
/** The node or one of its supernodes is managed by a class like ASRangeController. Most commonly, these nodes are
|
||||||
|
ASCellNode objects or a subnode of one, and are used in ASTableView or ASCollectionView.
|
||||||
|
These nodes also recieve regular updates to the .interfaceState property with more detailed status information. */
|
||||||
|
ASHierarchyStateRangeManaged = 1 << 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
@interface ASDisplayNode () <_ASDisplayLayerDelegate>
|
||||||
|
{
|
||||||
|
@protected
|
||||||
|
ASInterfaceState _interfaceState;
|
||||||
|
ASHierarchyState _hierarchyState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
|
||||||
|
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;
|
||||||
|
|
||||||
|
// These methods are recursive, and either union or remove the provided hierarchyState to all sub-elements.
|
||||||
|
- (void)enterHierarchyState:(ASHierarchyState)hierarchyState;
|
||||||
|
- (void)exitHierarchyState:(ASHierarchyState)hierarchyState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Returns the Hierarchy State of the node.
|
||||||
|
*
|
||||||
|
* @return The current ASHierarchyState of the node, indicating whether it is rasterized or managed by a range controller.
|
||||||
|
*
|
||||||
|
* @see ASInterfaceState
|
||||||
|
*/
|
||||||
|
@property (nonatomic, readwrite) ASHierarchyState hierarchyState;
|
||||||
|
|
||||||
|
// The two methods below will eventually be exposed, but their names are subject to change.
|
||||||
|
/**
|
||||||
|
* @abstract Ensure that all rendering is complete for this node and its descendents.
|
||||||
|
*
|
||||||
|
* @discussion Calling this method on the main thread after a node is added to the view heirarchy will ensure that
|
||||||
|
* placeholder states are never visible to the user. It is used by ASTableView, ASCollectionView, and ASViewController
|
||||||
|
* to implement their respective ".neverShowPlaceholders" option.
|
||||||
|
*
|
||||||
|
* If all nodes have layer.contents set and/or their layer does not have -needsDisplay set, the method will return immediately.
|
||||||
|
*
|
||||||
|
* This method is capable of handling a mixed set of nodes, with some not having started display, some in progress on an
|
||||||
|
* asynchronous display operation, and some already finished.
|
||||||
|
*
|
||||||
|
* In order to guarantee against deadlocks, this method should only be called on the main thread.
|
||||||
|
* It may block on the private queue, [_ASDisplayLayer displayQueue]
|
||||||
|
*/
|
||||||
|
- (void)recursivelyEnsureDisplay;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @abstract Allows a node to bypass all ensureDisplay passes. Defaults to NO.
|
||||||
|
*
|
||||||
|
* @discussion Nodes that are expensive to draw and expected to have placeholder even with
|
||||||
|
* .neverShowPlaceholders enabled should set this to YES.
|
||||||
|
*
|
||||||
|
* ASImageNode uses the default of NO, as it is often used for UI images that are expected to synchronize with ensureDisplay.
|
||||||
|
*
|
||||||
|
* ASNetworkImageNode and ASMultiplexImageNode set this to YES, because they load data from a database or server,
|
||||||
|
* and are expected to support a placeholder state given that display is often blocked on slow data fetching.
|
||||||
|
*/
|
||||||
|
@property (nonatomic, assign) BOOL shouldBypassEnsureDisplay;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface UIView (ASDisplayNodeInternal)
|
||||||
|
@property (nonatomic, assign, readwrite) ASDisplayNode *asyncdisplaykit_node;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface CALayer (ASDisplayNodeInternal)
|
||||||
|
@property (nonatomic, assign, readwrite) ASDisplayNode *asyncdisplaykit_node;
|
||||||
|
@end
|
||||||
@@ -8,9 +8,11 @@
|
|||||||
|
|
||||||
#import "_ASCoreAnimationExtras.h"
|
#import "_ASCoreAnimationExtras.h"
|
||||||
#import "_ASPendingState.h"
|
#import "_ASPendingState.h"
|
||||||
|
#import "ASInternalHelpers.h"
|
||||||
#import "ASAssert.h"
|
#import "ASAssert.h"
|
||||||
#import "ASDisplayNode+Subclasses.h"
|
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
|
#import "ASDisplayNode+Subclasses.h"
|
||||||
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
||||||
#import "ASEqualityHelpers.h"
|
#import "ASEqualityHelpers.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -219,9 +221,22 @@
|
|||||||
|
|
||||||
- (void)setNeedsDisplay
|
- (void)setNeedsDisplay
|
||||||
{
|
{
|
||||||
ASDisplayNode *rasterizedContainerNode = [self __rasterizedContainerNode];
|
if (_hierarchyState & ASHierarchyStateRasterized) {
|
||||||
if (rasterizedContainerNode) {
|
ASPerformBlockOnMainThread(^{
|
||||||
|
// The below operation must be performed on the main thread to ensure against an extremely rare deadlock, where a parent node
|
||||||
|
// begins materializing the view / layer heirarchy (locking itself or a descendant) while this node walks up
|
||||||
|
// the tree and requires locking that node to access .shouldRasterizeDescendants.
|
||||||
|
// For this reason, this method should be avoided when possible. Use _hierarchyState & ASHierarchyStateRasterized.
|
||||||
|
ASDisplayNodeAssertMainThread();
|
||||||
|
ASDisplayNode *rasterizedContainerNode = self.supernode;
|
||||||
|
while (rasterizedContainerNode) {
|
||||||
|
if (rasterizedContainerNode.shouldRasterizeDescendants) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
rasterizedContainerNode = rasterizedContainerNode.supernode;
|
||||||
|
}
|
||||||
[rasterizedContainerNode setNeedsDisplay];
|
[rasterizedContainerNode setNeedsDisplay];
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
[_layer setNeedsDisplay];
|
[_layer setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
|
BOOL ASDisplayNodeSubclassOverridesSelector(Class subclass, SEL selector);
|
||||||
void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)());
|
void ASDisplayNodeRespectThreadAffinityOfNode(ASDisplayNode *node, void (^block)());
|
||||||
|
|
||||||
typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||||
|
{
|
||||||
ASDisplayNodeMethodOverrideNone = 0,
|
ASDisplayNodeMethodOverrideNone = 0,
|
||||||
ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0,
|
ASDisplayNodeMethodOverrideTouchesBegan = 1 << 0,
|
||||||
ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1,
|
ASDisplayNodeMethodOverrideTouchesCancelled = 1 << 1,
|
||||||
@@ -73,8 +74,6 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
|||||||
|
|
||||||
_ASPendingState *_pendingViewState;
|
_ASPendingState *_pendingViewState;
|
||||||
|
|
||||||
ASInterfaceState _interfaceState;
|
|
||||||
|
|
||||||
struct ASDisplayNodeFlags {
|
struct ASDisplayNodeFlags {
|
||||||
// public properties
|
// public properties
|
||||||
unsigned synchronous:1;
|
unsigned synchronous:1;
|
||||||
@@ -118,9 +117,6 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
|||||||
// Bitmask to check which methods an object overrides.
|
// Bitmask to check which methods an object overrides.
|
||||||
@property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides;
|
@property (nonatomic, assign, readonly) ASDisplayNodeMethodOverrides methodOverrides;
|
||||||
|
|
||||||
// These methods are recursive, and either union or remove the provided interfaceState to all sub-elements.
|
|
||||||
- (void)enterInterfaceState:(ASInterfaceState)interfaceState;
|
|
||||||
- (void)exitInterfaceState:(ASInterfaceState)interfaceState;
|
|
||||||
|
|
||||||
// Swizzle to extend the builtin functionality with custom logic
|
// Swizzle to extend the builtin functionality with custom logic
|
||||||
- (BOOL)__shouldLoadViewOrLayer;
|
- (BOOL)__shouldLoadViewOrLayer;
|
||||||
@@ -149,9 +145,6 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
|||||||
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
// Display the node's view/layer immediately on the current thread, bypassing the background thread rendering. Will be deprecated.
|
||||||
- (void)displayImmediately;
|
- (void)displayImmediately;
|
||||||
|
|
||||||
// Returns the ancestor node that rasterizes descendants, or nil if none.
|
|
||||||
- (ASDisplayNode *)__rasterizedContainerNode;
|
|
||||||
|
|
||||||
// Alternative initialiser for backing with a custom view class. Supports asynchronous display with _ASDisplayView subclasses.
|
// Alternative initialiser for backing with a custom view class. Supports asynchronous display with _ASDisplayView subclasses.
|
||||||
- (id)initWithViewClass:(Class)viewClass;
|
- (id)initWithViewClass:(Class)viewClass;
|
||||||
|
|
||||||
@@ -160,12 +153,12 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides) {
|
|||||||
|
|
||||||
@property (nonatomic, assign) CGFloat contentsScaleForDisplay;
|
@property (nonatomic, assign) CGFloat contentsScaleForDisplay;
|
||||||
|
|
||||||
@end
|
/**
|
||||||
|
* This method has proven helpful in a few rare scenarios, similar to a category extension on UIView,
|
||||||
|
* but it's considered private API for now and its use should not be encouraged.
|
||||||
|
* @param checkViewHierarchy If YES, and no supernode can be found, method will walk up from `self.view` to find a supernode.
|
||||||
|
* If YES, this method must be called on the main thread and the node must not be layer-backed.
|
||||||
|
*/
|
||||||
|
- (ASDisplayNode *)_supernodeWithClass:(Class)supernodeClass checkViewHierarchy:(BOOL)checkViewHierarchy;
|
||||||
|
|
||||||
@interface UIView (ASDisplayNodeInternal)
|
|
||||||
@property (nonatomic, assign, readwrite) ASDisplayNode *asyncdisplaykit_node;
|
|
||||||
@end
|
|
||||||
|
|
||||||
@interface CALayer (ASDisplayNodeInternal)
|
|
||||||
@property (nonatomic, assign, readwrite) ASDisplayNode *asyncdisplaykit_node;
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -68,7 +68,7 @@
|
|||||||
{
|
{
|
||||||
// If it's a space character and we have custom word kerning, use the whitespace action control character.
|
// If it's a space character and we have custom word kerning, use the whitespace action control character.
|
||||||
if ([layoutManager.textStorage.string characterAtIndex:characterIndex] == ' ')
|
if ([layoutManager.textStorage.string characterAtIndex:characterIndex] == ' ')
|
||||||
return NSControlCharacterWhitespaceAction;
|
return NSControlCharacterActionWhitespace;
|
||||||
|
|
||||||
return defaultAction;
|
return defaultAction;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user