mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-11 15:10:37 +00:00
Introduce ASIndexedNodeContext
- It is a container object that holds enough information to construct and measure a cell node - All information is gathered on main thread. This allows ASDataController to capture the correct state of its data source before going to background.
This commit is contained in:
parent
3671f5cbc5
commit
54cde1a3db
@ -504,6 +504,10 @@
|
|||||||
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 */; };
|
||||||
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
DECBD6EA1BE56E1900CF4905 /* ASButtonNode.mm in Sources */ = {isa = PBXBuildFile; fileRef = DECBD6E61BE56E1900CF4905 /* ASButtonNode.mm */; };
|
||||||
|
E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */ = {isa = PBXBuildFile; fileRef = E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */; };
|
||||||
|
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */; };
|
||||||
|
E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */ = {isa = PBXBuildFile; fileRef = E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -659,7 +663,7 @@
|
|||||||
205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CGRect+ASConvenience.h"; sourceTree = "<group>"; };
|
205F0E1F1B376416007741D0 /* CGRect+ASConvenience.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CGRect+ASConvenience.h"; sourceTree = "<group>"; };
|
||||||
205F0E201B376416007741D0 /* CGRect+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CGRect+ASConvenience.m"; sourceTree = "<group>"; };
|
205F0E201B376416007741D0 /* CGRect+ASConvenience.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "CGRect+ASConvenience.m"; sourceTree = "<group>"; };
|
||||||
242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBasicImageDownloaderTests.m; sourceTree = "<group>"; };
|
242995D21B29743C00090100 /* ASBasicImageDownloaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASBasicImageDownloaderTests.m; sourceTree = "<group>"; };
|
||||||
251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASCollectionDataController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
251B8EF21BBB3D690087C538 /* ASCollectionDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASCollectionDataController.h; sourceTree = "<group>"; };
|
||||||
251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionDataController.mm; sourceTree = "<group>"; };
|
251B8EF31BBB3D690087C538 /* ASCollectionDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASCollectionDataController.mm; sourceTree = "<group>"; };
|
||||||
251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewFlowLayoutInspector.h; sourceTree = "<group>"; };
|
251B8EF41BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASCollectionViewFlowLayoutInspector.h; sourceTree = "<group>"; };
|
||||||
251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewFlowLayoutInspector.m; sourceTree = "<group>"; };
|
251B8EF51BBB3D690087C538 /* ASCollectionViewFlowLayoutInspector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASCollectionViewFlowLayoutInspector.m; sourceTree = "<group>"; };
|
||||||
@ -706,7 +710,7 @@
|
|||||||
3C9C128419E616EF00E942A0 /* ASTableViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASTableViewTests.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
3C9C128419E616EF00E942A0 /* ASTableViewTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ASTableViewTests.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||||
430E7C8D1B4C23F100697A4C /* ASIndexPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexPath.h; sourceTree = "<group>"; };
|
430E7C8D1B4C23F100697A4C /* ASIndexPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexPath.h; sourceTree = "<group>"; };
|
||||||
430E7C8E1B4C23F100697A4C /* ASIndexPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexPath.m; sourceTree = "<group>"; };
|
430E7C8E1B4C23F100697A4C /* ASIndexPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexPath.m; sourceTree = "<group>"; };
|
||||||
464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDataController.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
464052191A3F83C40061C0BA /* ASDataController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = ASDataController.h; sourceTree = "<group>"; };
|
||||||
4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDataController.mm; sourceTree = "<group>"; };
|
4640521A1A3F83C40061C0BA /* ASDataController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; lineEnding = 0; path = ASDataController.mm; sourceTree = "<group>"; };
|
||||||
4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASFlowLayoutController.h; sourceTree = "<group>"; };
|
4640521B1A3F83C40061C0BA /* ASFlowLayoutController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASFlowLayoutController.h; sourceTree = "<group>"; };
|
||||||
4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASFlowLayoutController.mm; sourceTree = "<group>"; };
|
4640521C1A3F83C40061C0BA /* ASFlowLayoutController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ASFlowLayoutController.mm; sourceTree = "<group>"; };
|
||||||
@ -826,6 +830,8 @@
|
|||||||
DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASCollectionInternal.m; path = Details/ASCollectionInternal.m; sourceTree = "<group>"; };
|
DEC146B51C37A16A004A0EE7 /* ASCollectionInternal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ASCollectionInternal.m; path = Details/ASCollectionInternal.m; 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>"; };
|
||||||
|
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIndexedNodeContext.h; sourceTree = "<group>"; };
|
||||||
|
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIndexedNodeContext.m; 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; };
|
||||||
FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = "<group>"; };
|
FB07EABBCF28656C6297BC2D /* Pods-AsyncDisplayKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AsyncDisplayKitTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-AsyncDisplayKitTests/Pods-AsyncDisplayKitTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@ -1250,6 +1256,8 @@
|
|||||||
4640521A1A3F83C40061C0BA /* ASDataController.mm */,
|
4640521A1A3F83C40061C0BA /* ASDataController.mm */,
|
||||||
AC026B671BD57D6F00BBC17E /* ASChangeSetDataController.h */,
|
AC026B671BD57D6F00BBC17E /* ASChangeSetDataController.h */,
|
||||||
AC026B681BD57D6F00BBC17E /* ASChangeSetDataController.m */,
|
AC026B681BD57D6F00BBC17E /* ASChangeSetDataController.m */,
|
||||||
|
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */,
|
||||||
|
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */,
|
||||||
);
|
);
|
||||||
name = "Data Controller";
|
name = "Data Controller";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1327,6 +1335,7 @@
|
|||||||
isa = PBXHeadersBuildPhase;
|
isa = PBXHeadersBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */,
|
||||||
257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */,
|
257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */,
|
||||||
A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */,
|
A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */,
|
||||||
92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */,
|
92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */,
|
||||||
@ -1567,6 +1576,7 @@
|
|||||||
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
|
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
|
||||||
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */,
|
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */,
|
||||||
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
|
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
|
||||||
|
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */,
|
||||||
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
|
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
|
||||||
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
|
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
|
||||||
254C6B761BF94DF4003EC431 /* ASTextNodeTypes.h in Headers */,
|
254C6B761BF94DF4003EC431 /* ASTextNodeTypes.h in Headers */,
|
||||||
@ -1857,6 +1867,7 @@
|
|||||||
205F0E121B371BD7007741D0 /* ASScrollDirection.m in Sources */,
|
205F0E121B371BD7007741D0 /* ASScrollDirection.m in Sources */,
|
||||||
9C8898BB1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */,
|
9C8898BB1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */,
|
||||||
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */,
|
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */,
|
||||||
|
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */,
|
||||||
058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */,
|
058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */,
|
||||||
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
|
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
|
||||||
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */,
|
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */,
|
||||||
@ -1965,6 +1976,7 @@
|
|||||||
B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */,
|
B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */,
|
||||||
DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */,
|
DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */,
|
||||||
254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */,
|
254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */,
|
||||||
|
E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */,
|
||||||
B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */,
|
B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */,
|
||||||
B35061FC1B010EFD0018CF92 /* ASDisplayNode.mm in Sources */,
|
B35061FC1B010EFD0018CF92 /* ASDisplayNode.mm in Sources */,
|
||||||
B35061FF1B010EFD0018CF92 /* ASDisplayNodeExtras.mm in Sources */,
|
B35061FF1B010EFD0018CF92 /* ASDisplayNodeExtras.mm in Sources */,
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#import "ASCellNode.h"
|
#import "ASCellNode.h"
|
||||||
#import "ASDisplayNodeInternal.h"
|
#import "ASDisplayNodeInternal.h"
|
||||||
#import "ASDataController+Subclasses.h"
|
#import "ASDataController+Subclasses.h"
|
||||||
|
#import "ASIndexedNodeContext.h"
|
||||||
|
|
||||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||||
#define LOG(...)
|
#define LOG(...)
|
||||||
@ -26,16 +27,14 @@
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation ASCollectionDataController {
|
@implementation ASCollectionDataController {
|
||||||
NSMutableDictionary<NSString *, NSMutableArray<ASCellNode *> *> *_pendingNodes;
|
NSMutableDictionary<NSString *, NSMutableArray<ASIndexedNodeContext *> *> *_pendingContexts;
|
||||||
NSMutableDictionary<NSString *, NSMutableArray<NSIndexPath *> *> *_pendingIndexPaths;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (instancetype)initWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
- (instancetype)initWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||||
{
|
{
|
||||||
self = [super initWithAsyncDataFetching:asyncDataFetchingEnabled];
|
self = [super initWithAsyncDataFetching:asyncDataFetchingEnabled];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_pendingNodes = [NSMutableDictionary dictionary];
|
_pendingContexts = [NSMutableDictionary dictionary];
|
||||||
_pendingIndexPaths = [NSMutableDictionary dictionary];
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -44,20 +43,18 @@
|
|||||||
{
|
{
|
||||||
for (NSString *kind in [self supplementaryKinds]) {
|
for (NSString *kind in [self supplementaryKinds]) {
|
||||||
LOG(@"Populating elements of kind: %@", kind);
|
LOG(@"Populating elements of kind: %@", kind);
|
||||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *nodes = [NSMutableArray array];
|
[self _populateSupplementaryNodesOfKind:kind withMutableContexts:contexts];
|
||||||
[self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
_pendingContexts[kind] = contexts;
|
||||||
_pendingNodes[kind] = nodes;
|
|
||||||
_pendingIndexPaths[kind] = indexPaths;
|
|
||||||
|
|
||||||
// Measure loaded nodes before leaving the main thread
|
// Measure loaded nodes before leaving the main thread
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willReloadData
|
- (void)willReloadData
|
||||||
{
|
{
|
||||||
[_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) {
|
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray<ASIndexedNodeContext *> *contexts, BOOL *stop) {
|
||||||
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
// Remove everything that existed before the reload, now that we're ready to insert replacements
|
||||||
NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind];
|
NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind];
|
||||||
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
|
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
@ -74,11 +71,10 @@
|
|||||||
}
|
}
|
||||||
[self insertSections:sections ofKind:kind atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] completion:nil];
|
[self insertSections:sections ofKind:kind atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] completion:nil];
|
||||||
|
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:_pendingIndexPaths[kind] completion:^(NSArray *nodes, NSArray *indexPaths) {
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
||||||
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
}];
|
}];
|
||||||
[_pendingNodes removeObjectForKey:kind];
|
[_pendingContexts removeObjectForKey:kind];
|
||||||
[_pendingIndexPaths removeObjectForKey:kind];
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,31 +82,28 @@
|
|||||||
{
|
{
|
||||||
for (NSString *kind in [self supplementaryKinds]) {
|
for (NSString *kind in [self supplementaryKinds]) {
|
||||||
LOG(@"Populating elements of kind: %@, for sections: %@", kind, sections);
|
LOG(@"Populating elements of kind: %@, for sections: %@", kind, sections);
|
||||||
NSMutableArray *nodes = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
|
||||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableNodes:nodes mutableIndexPaths:indexPaths];
|
_pendingContexts[kind] = contexts;
|
||||||
_pendingNodes[kind] = nodes;
|
|
||||||
_pendingIndexPaths[kind] = indexPaths;
|
|
||||||
|
|
||||||
// Measure loaded nodes before leaving the main thread
|
// Measure loaded nodes before leaving the main thread
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willInsertSections:(NSIndexSet *)sections
|
- (void)willInsertSections:(NSIndexSet *)sections
|
||||||
{
|
{
|
||||||
[_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) {
|
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray<ASIndexedNodeContext *> *contexts, BOOL *stop) {
|
||||||
NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:sections.count];
|
NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:sections.count];
|
||||||
for (NSUInteger i = 0; i < sections.count; i++) {
|
for (NSUInteger i = 0; i < sections.count; i++) {
|
||||||
[sectionArray addObject:[NSMutableArray array]];
|
[sectionArray addObject:[NSMutableArray array]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self insertSections:sectionArray ofKind:kind atIndexSet:sections completion:nil];
|
[self insertSections:sectionArray ofKind:kind atIndexSet:sections completion:nil];
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:_pendingIndexPaths[kind] completion:^(NSArray *nodes, NSArray *indexPaths) {
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
||||||
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
}];
|
}];
|
||||||
[_pendingNodes removeObjectForKey:kind];
|
[_pendingContexts removeObjectForKey:kind];
|
||||||
[_pendingIndexPaths removeObjectForKey:kind];
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,28 +120,25 @@
|
|||||||
- (void)prepareForReloadSections:(NSIndexSet *)sections
|
- (void)prepareForReloadSections:(NSIndexSet *)sections
|
||||||
{
|
{
|
||||||
for (NSString *kind in [self supplementaryKinds]) {
|
for (NSString *kind in [self supplementaryKinds]) {
|
||||||
NSMutableArray *nodes = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
|
||||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableNodes:nodes mutableIndexPaths:indexPaths];
|
_pendingContexts[kind] = contexts;
|
||||||
_pendingNodes[kind] = nodes;
|
|
||||||
_pendingIndexPaths[kind] = indexPaths;
|
|
||||||
|
|
||||||
// Measure loaded nodes before leaving the main thread
|
// Measure loaded nodes before leaving the main thread
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willReloadSections:(NSIndexSet *)sections
|
- (void)willReloadSections:(NSIndexSet *)sections
|
||||||
{
|
{
|
||||||
[_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) {
|
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray<ASIndexedNodeContext *> *contexts, BOOL *stop) {
|
||||||
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections);
|
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections);
|
||||||
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
|
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
// reinsert the elements
|
// reinsert the elements
|
||||||
[self batchLayoutNodes:nodes ofKind:kind atIndexPaths:_pendingIndexPaths[kind] completion:^(NSArray *nodes, NSArray *indexPaths) {
|
[self batchLayoutNodesFromContexts:contexts ofKind:kind completion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
||||||
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
[self insertNodes:nodes ofKind:kind atIndexPaths:indexPaths completion:nil];
|
||||||
}];
|
}];
|
||||||
[_pendingNodes removeObjectForKey:kind];
|
[_pendingContexts removeObjectForKey:kind];
|
||||||
[_pendingIndexPaths removeObjectForKey:kind];
|
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +159,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withMutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||||
{
|
{
|
||||||
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryNodeOfKind:kind];
|
NSUInteger sectionCount = [self.collectionDataSource dataController:self numberOfSectionsForSupplementaryNodeOfKind:kind];
|
||||||
for (NSUInteger i = 0; i < sectionCount; i++) {
|
for (NSUInteger i = 0; i < sectionCount; i++) {
|
||||||
@ -177,7 +167,7 @@
|
|||||||
NSUInteger rowCount = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:i];
|
NSUInteger rowCount = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:i];
|
||||||
for (NSUInteger j = 0; j < rowCount; j++) {
|
for (NSUInteger j = 0; j < rowCount; j++) {
|
||||||
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
||||||
[indexPaths addObject:indexPath];
|
|
||||||
ASCellNodeBlock supplementaryCellBlock;
|
ASCellNodeBlock supplementaryCellBlock;
|
||||||
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
||||||
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
||||||
@ -185,19 +175,24 @@
|
|||||||
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||||
supplementaryCellBlock = ^{ return supplementaryNode; };
|
supplementaryCellBlock = ^{ return supplementaryNode; };
|
||||||
}
|
}
|
||||||
[nodes addObject:supplementaryCellBlock];
|
|
||||||
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath];
|
||||||
|
ASIndexedNodeContext *context = [[ASIndexedNodeContext alloc] initWithNodeBlock:supplementaryCellBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize];
|
||||||
|
[contexts addObject:context];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withSections:(NSIndexSet *)sections mutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
- (void)_populateSupplementaryNodesOfKind:(NSString *)kind withSections:(NSIndexSet *)sections mutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||||
{
|
{
|
||||||
[sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
[sections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
||||||
NSUInteger rowNum = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:idx];
|
NSUInteger rowNum = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:idx];
|
||||||
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
||||||
for (NSUInteger i = 0; i < rowNum; i++) {
|
for (NSUInteger i = 0; i < rowNum; i++) {
|
||||||
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
||||||
[indexPaths addObject:indexPath];
|
|
||||||
ASCellNodeBlock supplementaryCellBlock;
|
ASCellNodeBlock supplementaryCellBlock;
|
||||||
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
||||||
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
||||||
@ -205,7 +200,12 @@
|
|||||||
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||||
supplementaryCellBlock = ^{ return supplementaryNode; };
|
supplementaryCellBlock = ^{ return supplementaryNode; };
|
||||||
}
|
}
|
||||||
[nodes addObject:supplementaryCellBlock];
|
|
||||||
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath];
|
||||||
|
ASIndexedNodeContext *context = [[ASIndexedNodeContext alloc] initWithNodeBlock:supplementaryCellBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize];
|
||||||
|
[contexts addObject:context];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,9 @@
|
|||||||
#ifndef ASDataControllerSubclasses_Included
|
#ifndef ASDataControllerSubclasses_Included
|
||||||
#define ASDataControllerSubclasses_Included
|
#define ASDataControllerSubclasses_Included
|
||||||
|
|
||||||
//#import "ASDataController.h"
|
@class ASIndexedNodeContext;
|
||||||
|
|
||||||
|
typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths);
|
||||||
|
|
||||||
@interface ASDataController (Subclasses)
|
@interface ASDataController (Subclasses)
|
||||||
|
|
||||||
@ -35,7 +37,7 @@
|
|||||||
/**
|
/**
|
||||||
* Measure and layout the given nodes in optimized batches, constraining each to a given size in `constrainedSizeForNodeOfKind:atIndexPath:`.
|
* Measure and layout the given nodes in optimized batches, constraining each to a given size in `constrainedSizeForNodeOfKind:atIndexPath:`.
|
||||||
*/
|
*/
|
||||||
- (void)batchLayoutNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock;
|
- (void)batchLayoutNodesFromContexts:(NSArray<ASIndexedNodeContext *> *)contexts ofKind:(NSString *)kind completion:(ASDataControllerCompletionBlock)completionBlock;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform measurement and layout of loaded nodes on the main thread, skipping unloaded nodes.
|
* Perform measurement and layout of loaded nodes on the main thread, skipping unloaded nodes.
|
||||||
@ -43,7 +45,7 @@
|
|||||||
* @discussion Once nodes have loaded their views, we can't layout in the background so this is a chance
|
* @discussion Once nodes have loaded their views, we can't layout in the background so this is a chance
|
||||||
* to do so immediately on the main thread.
|
* to do so immediately on the main thread.
|
||||||
*/
|
*/
|
||||||
- (void)layoutLoadedNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths;
|
- (void)layoutLoadedNodes:(NSArray<ASCellNode *> *)nodes fromContexts:(NSArray<ASIndexedNodeContext *> *)contexts ofKind:(NSString *)kind;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the size range for a specific node during the layout process.
|
* Provides the size range for a specific node during the layout process.
|
||||||
@ -55,12 +57,12 @@
|
|||||||
/**
|
/**
|
||||||
* Inserts the given nodes of the specified kind into the backing store, calling completion on the main thread when the write finishes.
|
* Inserts the given nodes of the specified kind into the backing store, calling completion on the main thread when the write finishes.
|
||||||
*/
|
*/
|
||||||
- (void)insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock;
|
- (void)insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given nodes of the specified kind in the backing store, calling completion on the main thread when the deletion finishes.
|
* Deletes the given nodes of the specified kind in the backing store, calling completion on the main thread when the deletion finishes.
|
||||||
*/
|
*/
|
||||||
- (void)deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock;
|
- (void)deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts the given sections of the specified kind in the backing store, calling completion on the main thread when finished.
|
* Inserts the given sections of the specified kind in the backing store, calling completion on the main thread when finished.
|
||||||
|
@ -19,6 +19,8 @@
|
|||||||
#import "ASMainSerialQueue.h"
|
#import "ASMainSerialQueue.h"
|
||||||
#import "ASMultidimensionalArrayUtils.h"
|
#import "ASMultidimensionalArrayUtils.h"
|
||||||
#import "ASThread.h"
|
#import "ASThread.h"
|
||||||
|
#import "ASIndexedNodeContext.h"
|
||||||
|
#import "ASDataController+Subclasses.h"
|
||||||
|
|
||||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||||
#define LOG(...)
|
#define LOG(...)
|
||||||
@ -110,27 +112,28 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
#pragma mark - Cell Layout
|
#pragma mark - Cell Layout
|
||||||
|
|
||||||
- (void)batchLayoutNodes:(NSArray<ASCellNodeBlock> *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray<NSIndexPath *> *)indexPaths completion:(void (^)(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths))completionBlock
|
- (void)batchLayoutNodesFromContexts:(NSArray<ASIndexedNodeContext *> *)contexts ofKind:(NSString *)kind completion:(ASDataControllerCompletionBlock)completionBlock
|
||||||
{
|
{
|
||||||
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
|
NSUInteger blockSize = [[ASDataController class] parallelProcessorCount] * kASDataControllerSizingCountPerProcessor;
|
||||||
|
NSUInteger count = contexts.count;
|
||||||
|
|
||||||
// Processing in batches
|
// Processing in batches
|
||||||
for (NSUInteger i = 0; i < indexPaths.count; i += blockSize) {
|
for (NSUInteger i = 0; i < count; i += blockSize) {
|
||||||
NSRange batchedRange = NSMakeRange(i, MIN(indexPaths.count - i, blockSize));
|
NSRange batchedRange = NSMakeRange(i, MIN(count - i, blockSize));
|
||||||
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
|
NSArray<ASIndexedNodeContext *> *batchedContexts = [contexts subarrayWithRange:batchedRange];
|
||||||
NSArray *batchedNodes = [nodes subarrayWithRange:batchedRange];
|
[self _layoutNodesFromContexts:batchedContexts ofKind:kind completion:completionBlock];
|
||||||
[self _layoutNodes:batchedNodes ofKind:kind atIndexPaths:batchedIndexPaths completion:completionBlock];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)layoutLoadedNodes:(NSArray<ASCellNode *> *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray<NSIndexPath *> *)indexPaths {
|
- (void)layoutLoadedNodes:(NSArray<ASCellNode *> *)nodes fromContexts:(NSArray<ASIndexedNodeContext *> *)contexts ofKind:(NSString *)kind
|
||||||
|
{
|
||||||
NSAssert(NSThread.isMainThread, @"Main thread layout must be on the main thread.");
|
NSAssert(NSThread.isMainThread, @"Main thread layout must be on the main thread.");
|
||||||
|
ASDisplayNodeAssertTrue(nodes.count == contexts.count);
|
||||||
|
|
||||||
[indexPaths enumerateObjectsUsingBlock:^(NSIndexPath *indexPath, NSUInteger idx, __unused BOOL * stop) {
|
[contexts enumerateObjectsUsingBlock:^(ASIndexedNodeContext *context, NSUInteger idx, __unused BOOL * stop) {
|
||||||
ASCellNode *node = nodes[idx];
|
ASCellNode *node = nodes[idx];
|
||||||
if (node.isNodeLoaded) {
|
if (node.isNodeLoaded) {
|
||||||
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath];
|
[self _layoutNode:node withConstrainedSize:context.constrainedSize];
|
||||||
[self _layoutNode:node withConstrainedSize:constrainedSize];
|
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
@ -147,27 +150,26 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
/**
|
/**
|
||||||
* Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store.
|
* Measures and defines the layout for each node in optimized batches on an editing queue, inserting the results into the backing store.
|
||||||
*/
|
*/
|
||||||
- (void)_batchLayoutNodes:(NSArray *)nodes atIndexPaths:(NSArray *)indexPaths withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
- (void)_batchLayoutNodesFromContexts:(NSArray<ASIndexedNodeContext *> *)contexts withAnimationOptions:(ASDataControllerAnimationOptions)animationOptions
|
||||||
{
|
{
|
||||||
[self batchLayoutNodes:nodes ofKind:ASDataControllerRowNodeKind atIndexPaths:indexPaths completion:^(NSArray *nodes, NSArray *indexPaths) {
|
[self batchLayoutNodesFromContexts:contexts ofKind:ASDataControllerRowNodeKind completion:^(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths) {
|
||||||
// Insert finished nodes into data storage
|
// Insert finished nodes into data storage
|
||||||
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _insertNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_layoutNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
|
- (void)_layoutNodesFromContexts:(NSArray<ASIndexedNodeContext *> *)contexts ofKind:(NSString *)kind completion:(ASDataControllerCompletionBlock)completionBlock
|
||||||
{
|
{
|
||||||
if (!nodes.count) {
|
if (!contexts.count) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSUInteger nodeCount = nodes.count;
|
NSUInteger nodeCount = contexts.count;
|
||||||
NSMutableArray<ASCellNode *> *allocatedNodes = [NSMutableArray<ASCellNode *> arrayWithCapacity:nodeCount];
|
NSMutableArray<ASCellNode *> *allocatedNodes = [NSMutableArray<ASCellNode *> arrayWithCapacity:nodeCount];
|
||||||
dispatch_group_t layoutGroup = dispatch_group_create();
|
dispatch_group_t layoutGroup = dispatch_group_create();
|
||||||
ASSizeRange *nodeBoundSizes = (ASSizeRange *)malloc(sizeof(ASSizeRange) * nodeCount);
|
|
||||||
|
|
||||||
for (NSUInteger j = 0; j < nodes.count && j < indexPaths.count; j += kASDataControllerSizingCountPerProcessor) {
|
for (NSUInteger j = 0; j < nodeCount; j += kASDataControllerSizingCountPerProcessor) {
|
||||||
NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, indexPaths.count - j);
|
NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, nodeCount - j);
|
||||||
|
|
||||||
__block NSArray *subarray;
|
__block NSArray *subarray;
|
||||||
// Allocate nodes concurrently.
|
// Allocate nodes concurrently.
|
||||||
@ -176,13 +178,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||||
dispatch_apply(batchCount, queue, ^(size_t i) {
|
dispatch_apply(batchCount, queue, ^(size_t i) {
|
||||||
unsigned long k = j + i;
|
unsigned long k = j + i;
|
||||||
ASCellNodeBlock cellBlock = nodes[k];
|
ASIndexedNodeContext *context = contexts[k];
|
||||||
ASCellNode *node = cellBlock();
|
ASCellNodeBlock nodeBlock = context.nodeBlock;
|
||||||
|
ASCellNode *node = nodeBlock();
|
||||||
ASDisplayNodeAssertNotNil(node, @"Node block created nil node");
|
ASDisplayNodeAssertNotNil(node, @"Node block created nil node");
|
||||||
allocatedNodeBuffer[i] = node;
|
allocatedNodeBuffer[i] = node;
|
||||||
if (!node.isNodeLoaded) {
|
|
||||||
nodeBoundSizes[k] = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPaths[k]];
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
subarray = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount];
|
subarray = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount];
|
||||||
|
|
||||||
@ -200,11 +200,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
dispatch_semaphore_signal(sema);
|
dispatch_semaphore_signal(sema);
|
||||||
});
|
});
|
||||||
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
|
||||||
[self layoutLoadedNodes:subarray ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]];
|
[self layoutLoadedNodes:subarray fromContexts:[contexts subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind];
|
||||||
} else {
|
} else {
|
||||||
allocationBlock();
|
allocationBlock();
|
||||||
[_mainSerialQueue performBlockOnMainThread:^{
|
[_mainSerialQueue performBlockOnMainThread:^{
|
||||||
[self layoutLoadedNodes:subarray ofKind:kind atIndexPaths:[indexPaths subarrayWithRange:NSMakeRange(j, batchCount)]];
|
[self layoutLoadedNodes:subarray fromContexts:[contexts subarrayWithRange:NSMakeRange(j, batchCount)] ofKind:kind];
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
// Only measure nodes whose views aren't loaded, since we're in the background.
|
// Only measure nodes whose views aren't loaded, since we're in the background.
|
||||||
// We should already have measured loaded nodes before we left the main thread, using layoutLoadedNodes:ofKind:atIndexPaths:
|
// We should already have measured loaded nodes before we left the main thread, using layoutLoadedNodes:ofKind:atIndexPaths:
|
||||||
if (!node.isNodeLoaded) {
|
if (!node.isNodeLoaded) {
|
||||||
[self _layoutNode:node withConstrainedSize:nodeBoundSizes[k]];
|
[self _layoutNode:node withConstrainedSize:contexts[k].constrainedSize];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -224,9 +224,13 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
// Block the _editingTransactionQueue from executing a new edit transaction until layout is done & _editingNodes array is updated.
|
// Block the _editingTransactionQueue from executing a new edit transaction until layout is done & _editingNodes array is updated.
|
||||||
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
|
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
|
||||||
free(nodeBoundSizes);
|
|
||||||
|
|
||||||
if (completionBlock) {
|
if (completionBlock) {
|
||||||
|
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:nodeCount];
|
||||||
|
[contexts enumerateObjectsUsingBlock:^(ASIndexedNodeContext * _Nonnull context, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||||
|
[indexPaths addObject:context.indexPath];
|
||||||
|
}];
|
||||||
|
|
||||||
completionBlock(allocatedNodes, indexPaths);
|
completionBlock(allocatedNodes, indexPaths);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,10 +242,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
#pragma mark - External Data Querying + Editing
|
#pragma mark - External Data Querying + Editing
|
||||||
|
|
||||||
- (void)insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
|
- (void)insertNodes:(NSArray *)nodes ofKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock
|
||||||
{
|
{
|
||||||
if (indexPaths.count == 0)
|
if (indexPaths.count == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
NSMutableArray *editingNodes = _editingNodes[kind];
|
NSMutableArray *editingNodes = _editingNodes[kind];
|
||||||
ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths, nodes);
|
ASInsertElementsIntoMultidimensionalArrayAtIndexPaths(editingNodes, indexPaths, nodes);
|
||||||
@ -258,7 +263,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(void (^)(NSArray *nodes, NSArray *indexPaths))completionBlock
|
- (void)deleteNodesOfKind:(NSString *)kind atIndexPaths:(NSArray *)indexPaths completion:(ASDataControllerCompletionBlock)completionBlock
|
||||||
{
|
{
|
||||||
if (indexPaths.count == 0) {
|
if (indexPaths.count == 0) {
|
||||||
return;
|
return;
|
||||||
@ -417,9 +422,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
[self accessDataSourceSynchronously:synchronously withBlock:^{
|
[self accessDataSourceSynchronously:synchronously withBlock:^{
|
||||||
NSUInteger sectionCount = [_dataSource numberOfSectionsInDataController:self];
|
NSUInteger sectionCount = [_dataSource numberOfSectionsInDataController:self];
|
||||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
[self _populateFromEntireDataSourceWithMutableContexts:contexts];
|
||||||
[self _populateFromEntireDataSourceWithMutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
|
||||||
|
|
||||||
// Allow subclasses to perform setup before going into the edit transaction
|
// Allow subclasses to perform setup before going into the edit transaction
|
||||||
[self prepareForReloadData];
|
[self prepareForReloadData];
|
||||||
@ -445,7 +449,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
[self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withAnimationOptions:animationOptions];
|
[self _insertSections:sections atIndexSet:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withAnimationOptions:animationOptions];
|
||||||
|
|
||||||
[self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
[self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
|
|
||||||
if (completion) {
|
if (completion) {
|
||||||
dispatch_async(dispatch_get_main_queue(), completion);
|
dispatch_async(dispatch_get_main_queue(), completion);
|
||||||
@ -489,29 +493,32 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches row nodes and their specified index paths for the provided sections from the data source.
|
* Fetches row contexts for the provided sections from the data source.
|
||||||
*
|
*
|
||||||
* @discussion Results are stored in the passed mutable arrays.
|
* @discussion Results are stored in the passed mutable arrays.
|
||||||
*/
|
*/
|
||||||
- (void)_populateFromDataSourceWithSectionIndexSet:(NSIndexSet *)indexSet mutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
- (void)_populateFromDataSourceWithSectionIndexSet:(NSIndexSet *)indexSet mutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||||
{
|
{
|
||||||
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
||||||
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:idx];
|
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:idx];
|
||||||
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
||||||
for (NSUInteger i = 0; i < rowNum; i++) {
|
for (NSUInteger i = 0; i < rowNum; i++) {
|
||||||
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
||||||
[indexPaths addObject:indexPath];
|
ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
|
||||||
[nodes addObject:[_dataSource dataController:self nodeBlockAtIndexPath:indexPath]];
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath];
|
||||||
|
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize]];
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches row nodes and their specified index paths for all sections from the data source.
|
* Fetches row contexts for all sections from the data source.
|
||||||
*
|
*
|
||||||
* @discussion Results are stored in the passed mutable arrays.
|
* @discussion Results are stored in the passed mutable arrays.
|
||||||
*/
|
*/
|
||||||
- (void)_populateFromEntireDataSourceWithMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
- (void)_populateFromEntireDataSourceWithMutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||||
{
|
{
|
||||||
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
|
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
|
||||||
for (NSUInteger i = 0; i < sectionNum; i++) {
|
for (NSUInteger i = 0; i < sectionNum; i++) {
|
||||||
@ -519,8 +526,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:i];
|
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:i];
|
||||||
for (NSUInteger j = 0; j < rowNum; j++) {
|
for (NSUInteger j = 0; j < rowNum; j++) {
|
||||||
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
||||||
[indexPaths addObject:indexPath];
|
ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
|
||||||
[nodes addObject:[_dataSource dataController:self nodeBlockAtIndexPath:indexPath]];
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath];
|
||||||
|
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -607,9 +617,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
||||||
|
|
||||||
[self accessDataSourceWithBlock:^{
|
[self accessDataSourceWithBlock:^{
|
||||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
[self _populateFromDataSourceWithSectionIndexSet:sections mutableContexts:contexts];
|
||||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
|
||||||
|
|
||||||
[self prepareForInsertSections:sections];
|
[self prepareForInsertSections:sections];
|
||||||
|
|
||||||
@ -623,7 +632,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self _insertSections:sectionArray atIndexSet:sections withAnimationOptions:animationOptions];
|
[self _insertSections:sectionArray atIndexSet:sections withAnimationOptions:animationOptions];
|
||||||
[self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
|
||||||
|
[self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
@ -658,9 +668,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
||||||
|
|
||||||
[self accessDataSourceWithBlock:^{
|
[self accessDataSourceWithBlock:^{
|
||||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
[self _populateFromDataSourceWithSectionIndexSet:sections mutableContexts:contexts];
|
||||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
|
||||||
|
|
||||||
[self prepareForReloadSections:sections];
|
[self prepareForReloadSections:sections];
|
||||||
|
|
||||||
@ -674,7 +683,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
|
|
||||||
// reinsert the elements
|
// reinsert the elements
|
||||||
[self _batchLayoutNodes:updatedNodes atIndexPaths:updatedIndexPaths withAnimationOptions:animationOptions];
|
[self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
@ -768,14 +777,20 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
[self accessDataSourceWithBlock:^{
|
[self accessDataSourceWithBlock:^{
|
||||||
// sort indexPath to avoid messing up the index when inserting in several batches
|
// sort indexPath to avoid messing up the index when inserting in several batches
|
||||||
NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)];
|
NSArray *sortedIndexPaths = [indexPaths sortedArrayUsingSelector:@selector(compare:)];
|
||||||
NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
||||||
|
|
||||||
for (NSUInteger i = 0; i < sortedIndexPaths.count; i++) {
|
for (NSUInteger i = 0; i < sortedIndexPaths.count; i++) {
|
||||||
[nodes addObject:[_dataSource dataController:self nodeBlockAtIndexPath:sortedIndexPaths[i]]];
|
NSIndexPath *indexPath = sortedIndexPaths[i];
|
||||||
|
ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
|
||||||
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath];
|
||||||
|
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_editingTransactionQueue addOperationWithBlock:^{
|
[_editingTransactionQueue addOperationWithBlock:^{
|
||||||
LOG(@"Edit Transaction - insertRows: %@", indexPaths);
|
LOG(@"Edit Transaction - insertRows: %@", indexPaths);
|
||||||
[self _batchLayoutNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
@ -810,20 +825,24 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
|||||||
|
|
||||||
// Reloading requires re-fetching the data. Load it on the current calling thread, locking the data source.
|
// Reloading requires re-fetching the data. Load it on the current calling thread, locking the data source.
|
||||||
[self accessDataSourceWithBlock:^{
|
[self accessDataSourceWithBlock:^{
|
||||||
NSMutableArray *nodes = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
NSMutableArray<ASIndexedNodeContext *> *contexts = [[NSMutableArray alloc] initWithCapacity:indexPaths.count];
|
||||||
|
|
||||||
// FIXME: This doesn't currently do anything
|
// FIXME: This doesn't currently do anything
|
||||||
// FIXME: Shouldn't deletes be sorted in descending order?
|
// FIXME: Shouldn't deletes be sorted in descending order?
|
||||||
[indexPaths sortedArrayUsingSelector:@selector(compare:)];
|
[indexPaths sortedArrayUsingSelector:@selector(compare:)];
|
||||||
|
|
||||||
for (NSIndexPath *indexPath in indexPaths) {
|
for (NSIndexPath *indexPath in indexPaths) {
|
||||||
[nodes addObject:[_dataSource dataController:self nodeBlockAtIndexPath:indexPath]];
|
ASCellNodeBlock nodeBlock = [_dataSource dataController:self nodeBlockAtIndexPath:indexPath];
|
||||||
|
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:ASDataControllerRowNodeKind atIndexPath:indexPath];
|
||||||
|
[contexts addObject:[[ASIndexedNodeContext alloc] initWithNodeBlock:nodeBlock
|
||||||
|
indexPath:indexPath
|
||||||
|
constrainedSize:constrainedSize]];
|
||||||
}
|
}
|
||||||
|
|
||||||
[_editingTransactionQueue addOperationWithBlock:^{
|
[_editingTransactionQueue addOperationWithBlock:^{
|
||||||
LOG(@"Edit Transaction - reloadRows: %@", indexPaths);
|
LOG(@"Edit Transaction - reloadRows: %@", indexPaths);
|
||||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||||
[self _batchLayoutNodes:nodes atIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
[self _batchLayoutNodesFromContexts:contexts withAnimationOptions:animationOptions];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
}];
|
}];
|
||||||
|
22
AsyncDisplayKit/Details/ASIndexedNodeContext.h
Normal file
22
AsyncDisplayKit/Details/ASIndexedNodeContext.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
//
|
||||||
|
// ASIndexedNodeContext.h
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Huy Nguyen on 2/28/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <AsyncDisplayKit/ASDataController.h>
|
||||||
|
#import <AsyncDisplayKit/ASDimension.h>
|
||||||
|
|
||||||
|
@interface ASIndexedNodeContext : NSObject
|
||||||
|
|
||||||
|
@property (nonatomic, readonly, strong) ASCellNodeBlock nodeBlock;
|
||||||
|
@property (nonatomic, readonly, assign) NSIndexPath *indexPath;
|
||||||
|
@property (nonatomic, readonly, assign) ASSizeRange constrainedSize;
|
||||||
|
|
||||||
|
- (instancetype)initWithNodeBlock:(ASCellNodeBlock)nodeBlock
|
||||||
|
indexPath:(NSIndexPath *)indexPath
|
||||||
|
constrainedSize:(ASSizeRange)constrainedSize;
|
||||||
|
|
||||||
|
@end
|
26
AsyncDisplayKit/Details/ASIndexedNodeContext.m
Normal file
26
AsyncDisplayKit/Details/ASIndexedNodeContext.m
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// ASIndexedNodeContext.m
|
||||||
|
// AsyncDisplayKit
|
||||||
|
//
|
||||||
|
// Created by Huy Nguyen on 2/28/16.
|
||||||
|
// Copyright © 2016 Facebook. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "ASIndexedNodeContext.h"
|
||||||
|
|
||||||
|
@implementation ASIndexedNodeContext
|
||||||
|
|
||||||
|
- (instancetype)initWithNodeBlock:(ASCellNodeBlock)nodeBlock
|
||||||
|
indexPath:(NSIndexPath *)indexPath
|
||||||
|
constrainedSize:(ASSizeRange)constrainedSize;
|
||||||
|
{
|
||||||
|
self = [super init];
|
||||||
|
if (self) {
|
||||||
|
_nodeBlock = nodeBlock;
|
||||||
|
_indexPath = indexPath;
|
||||||
|
_constrainedSize = constrainedSize;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
Loading…
x
Reference in New Issue
Block a user