mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-07 05:02:56 +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, ); }; };
|
||||
DECBD6E91BE56E1900CF4905 /* 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 */
|
||||
|
||||
/* 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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -826,6 +830,8 @@
|
||||
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>"; };
|
||||
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; };
|
||||
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 */
|
||||
@ -1250,6 +1256,8 @@
|
||||
4640521A1A3F83C40061C0BA /* ASDataController.mm */,
|
||||
AC026B671BD57D6F00BBC17E /* ASChangeSetDataController.h */,
|
||||
AC026B681BD57D6F00BBC17E /* ASChangeSetDataController.m */,
|
||||
E5711A2A1C840C81009619D4 /* ASIndexedNodeContext.h */,
|
||||
E5711A2D1C840C96009619D4 /* ASIndexedNodeContext.m */,
|
||||
);
|
||||
name = "Data Controller";
|
||||
sourceTree = "<group>";
|
||||
@ -1327,6 +1335,7 @@
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
E5711A2B1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */,
|
||||
257754C21BEE458E00737CA5 /* ASTextKitCoreTextAdditions.h in Headers */,
|
||||
A373200F1C571B730011FC94 /* ASTextNode+Beta.h in Headers */,
|
||||
92DD2FE31BF4B97E0074C9DD /* ASMapNode.h in Headers */,
|
||||
@ -1567,6 +1576,7 @@
|
||||
9C49C3701B853961000B0DD5 /* ASStackLayoutable.h in Headers */,
|
||||
DE040EF91C2B40AC004692FF /* ASCollectionViewFlowLayoutInspector.h in Headers */,
|
||||
34EFC7701B701CFA00AD841F /* ASStackLayoutDefines.h in Headers */,
|
||||
E5711A2C1C840C81009619D4 /* ASIndexedNodeContext.h in Headers */,
|
||||
254C6B7B1BF94DF4003EC431 /* ASTextKitRenderer+Positioning.h in Headers */,
|
||||
CC7FD9E21BB603FF005CCB2B /* ASPhotosFrameworkImageRequest.h in Headers */,
|
||||
254C6B761BF94DF4003EC431 /* ASTextNodeTypes.h in Headers */,
|
||||
@ -1857,6 +1867,7 @@
|
||||
205F0E121B371BD7007741D0 /* ASScrollDirection.m in Sources */,
|
||||
9C8898BB1C738B9800D6B02E /* ASTextKitFontSizeAdjuster.mm in Sources */,
|
||||
D785F6631A74327E00291744 /* ASScrollNode.m in Sources */,
|
||||
E5711A2E1C840C96009619D4 /* ASIndexedNodeContext.m in Sources */,
|
||||
058D0A2C195D050800B7D73C /* ASSentinel.m in Sources */,
|
||||
9C8221971BA237B80037F19A /* ASStackBaselinePositionedLayout.mm in Sources */,
|
||||
251B8EF81BBB3D690087C538 /* ASCollectionDataController.mm in Sources */,
|
||||
@ -1965,6 +1976,7 @@
|
||||
B35062501B010EFD0018CF92 /* ASDisplayNode+DebugTiming.mm in Sources */,
|
||||
DEC146B91C37A16A004A0EE7 /* ASCollectionInternal.m in Sources */,
|
||||
254C6B891BF94F8A003EC431 /* ASTextKitRenderer+Positioning.mm in Sources */,
|
||||
E5711A301C840C96009619D4 /* ASIndexedNodeContext.m in Sources */,
|
||||
B35062511B010EFD0018CF92 /* ASDisplayNode+UIViewBridge.mm in Sources */,
|
||||
B35061FC1B010EFD0018CF92 /* ASDisplayNode.mm in Sources */,
|
||||
B35061FF1B010EFD0018CF92 /* ASDisplayNodeExtras.mm in Sources */,
|
||||
|
@ -13,6 +13,7 @@
|
||||
#import "ASCellNode.h"
|
||||
#import "ASDisplayNodeInternal.h"
|
||||
#import "ASDataController+Subclasses.h"
|
||||
#import "ASIndexedNodeContext.h"
|
||||
|
||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||
#define LOG(...)
|
||||
@ -26,16 +27,14 @@
|
||||
@end
|
||||
|
||||
@implementation ASCollectionDataController {
|
||||
NSMutableDictionary<NSString *, NSMutableArray<ASCellNode *> *> *_pendingNodes;
|
||||
NSMutableDictionary<NSString *, NSMutableArray<NSIndexPath *> *> *_pendingIndexPaths;
|
||||
NSMutableDictionary<NSString *, NSMutableArray<ASIndexedNodeContext *> *> *_pendingContexts;
|
||||
}
|
||||
|
||||
- (instancetype)initWithAsyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
self = [super initWithAsyncDataFetching:asyncDataFetchingEnabled];
|
||||
if (self != nil) {
|
||||
_pendingNodes = [NSMutableDictionary dictionary];
|
||||
_pendingIndexPaths = [NSMutableDictionary dictionary];
|
||||
_pendingContexts = [NSMutableDictionary dictionary];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -44,20 +43,18 @@
|
||||
{
|
||||
for (NSString *kind in [self supplementaryKinds]) {
|
||||
LOG(@"Populating elements of kind: %@", kind);
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
NSMutableArray *nodes = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withMutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||
_pendingNodes[kind] = nodes;
|
||||
_pendingIndexPaths[kind] = indexPaths;
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withMutableContexts:contexts];
|
||||
_pendingContexts[kind] = contexts;
|
||||
|
||||
// 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
|
||||
{
|
||||
[_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
|
||||
NSArray *indexPaths = [self indexPathsForEditingNodesOfKind:kind];
|
||||
[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 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];
|
||||
}];
|
||||
[_pendingNodes removeObjectForKey:kind];
|
||||
[_pendingIndexPaths removeObjectForKey:kind];
|
||||
[_pendingContexts removeObjectForKey:kind];
|
||||
}];
|
||||
}
|
||||
|
||||
@ -86,31 +82,28 @@
|
||||
{
|
||||
for (NSString *kind in [self supplementaryKinds]) {
|
||||
LOG(@"Populating elements of kind: %@, for sections: %@", kind, sections);
|
||||
NSMutableArray *nodes = [NSMutableArray array];
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||
_pendingNodes[kind] = nodes;
|
||||
_pendingIndexPaths[kind] = indexPaths;
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
|
||||
_pendingContexts[kind] = contexts;
|
||||
|
||||
// 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
|
||||
{
|
||||
[_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) {
|
||||
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray<ASIndexedNodeContext *> *contexts, BOOL *stop) {
|
||||
NSMutableArray *sectionArray = [NSMutableArray arrayWithCapacity:sections.count];
|
||||
for (NSUInteger i = 0; i < sections.count; i++) {
|
||||
[sectionArray addObject:[NSMutableArray array]];
|
||||
}
|
||||
|
||||
[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];
|
||||
}];
|
||||
[_pendingNodes removeObjectForKey:kind];
|
||||
[_pendingIndexPaths removeObjectForKey:kind];
|
||||
[_pendingContexts removeObjectForKey:kind];
|
||||
}];
|
||||
}
|
||||
|
||||
@ -127,28 +120,25 @@
|
||||
- (void)prepareForReloadSections:(NSIndexSet *)sections
|
||||
{
|
||||
for (NSString *kind in [self supplementaryKinds]) {
|
||||
NSMutableArray *nodes = [NSMutableArray array];
|
||||
NSMutableArray *indexPaths = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableNodes:nodes mutableIndexPaths:indexPaths];
|
||||
_pendingNodes[kind] = nodes;
|
||||
_pendingIndexPaths[kind] = indexPaths;
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateSupplementaryNodesOfKind:kind withSections:sections mutableContexts:contexts];
|
||||
_pendingContexts[kind] = contexts;
|
||||
|
||||
// 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
|
||||
{
|
||||
[_pendingNodes enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray *nodes, BOOL *stop) {
|
||||
[_pendingContexts enumerateKeysAndObjectsUsingBlock:^(NSString *kind, NSMutableArray<ASIndexedNodeContext *> *contexts, BOOL *stop) {
|
||||
NSArray *indexPaths = ASIndexPathsForMultidimensionalArrayAtIndexSet([self editingNodesOfKind:kind], sections);
|
||||
[self deleteNodesOfKind:kind atIndexPaths:indexPaths completion:nil];
|
||||
// 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];
|
||||
}];
|
||||
[_pendingNodes removeObjectForKey:kind];
|
||||
[_pendingIndexPaths removeObjectForKey:kind];
|
||||
[_pendingContexts 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];
|
||||
for (NSUInteger i = 0; i < sectionCount; i++) {
|
||||
@ -177,7 +167,7 @@
|
||||
NSUInteger rowCount = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:i];
|
||||
for (NSUInteger j = 0; j < rowCount; j++) {
|
||||
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
||||
[indexPaths addObject:indexPath];
|
||||
|
||||
ASCellNodeBlock supplementaryCellBlock;
|
||||
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
||||
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
||||
@ -185,19 +175,24 @@
|
||||
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||
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) {
|
||||
NSUInteger rowNum = [self.collectionDataSource dataController:self supplementaryNodesOfKind:kind inSection:idx];
|
||||
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
||||
for (NSUInteger i = 0; i < rowNum; i++) {
|
||||
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
||||
[indexPaths addObject:indexPath];
|
||||
|
||||
ASCellNodeBlock supplementaryCellBlock;
|
||||
if (_dataSourceImplementsSupplementaryNodeBlockOfKindAtIndexPath) {
|
||||
supplementaryCellBlock = [self.collectionDataSource dataController:self supplementaryNodeBlockOfKind:kind atIndexPath:indexPath];
|
||||
@ -205,7 +200,12 @@
|
||||
ASCellNode *supplementaryNode = [self.collectionDataSource dataController:self supplementaryNodeOfKind:kind atIndexPath:indexPath];
|
||||
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
|
||||
#define ASDataControllerSubclasses_Included
|
||||
|
||||
//#import "ASDataController.h"
|
||||
@class ASIndexedNodeContext;
|
||||
|
||||
typedef void (^ASDataControllerCompletionBlock)(NSArray<ASCellNode *> *nodes, NSArray<NSIndexPath *> *indexPaths);
|
||||
|
||||
@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:`.
|
||||
*/
|
||||
- (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.
|
||||
@ -43,7 +45,7 @@
|
||||
* @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.
|
||||
*/
|
||||
- (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.
|
||||
@ -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.
|
||||
*/
|
||||
- (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.
|
||||
*/
|
||||
- (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.
|
||||
|
@ -19,6 +19,8 @@
|
||||
#import "ASMainSerialQueue.h"
|
||||
#import "ASMultidimensionalArrayUtils.h"
|
||||
#import "ASThread.h"
|
||||
#import "ASIndexedNodeContext.h"
|
||||
#import "ASDataController+Subclasses.h"
|
||||
|
||||
//#define LOG(...) NSLog(__VA_ARGS__)
|
||||
#define LOG(...)
|
||||
@ -110,27 +112,28 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
|
||||
#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 count = contexts.count;
|
||||
|
||||
// Processing in batches
|
||||
for (NSUInteger i = 0; i < indexPaths.count; i += blockSize) {
|
||||
NSRange batchedRange = NSMakeRange(i, MIN(indexPaths.count - i, blockSize));
|
||||
NSArray *batchedIndexPaths = [indexPaths subarrayWithRange:batchedRange];
|
||||
NSArray *batchedNodes = [nodes subarrayWithRange:batchedRange];
|
||||
[self _layoutNodes:batchedNodes ofKind:kind atIndexPaths:batchedIndexPaths completion:completionBlock];
|
||||
for (NSUInteger i = 0; i < count; i += blockSize) {
|
||||
NSRange batchedRange = NSMakeRange(i, MIN(count - i, blockSize));
|
||||
NSArray<ASIndexedNodeContext *> *batchedContexts = [contexts subarrayWithRange:batchedRange];
|
||||
[self _layoutNodesFromContexts:batchedContexts ofKind:kind 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.");
|
||||
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];
|
||||
if (node.isNodeLoaded) {
|
||||
ASSizeRange constrainedSize = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPath];
|
||||
[self _layoutNode:node withConstrainedSize:constrainedSize];
|
||||
[self _layoutNode:node withConstrainedSize:context.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.
|
||||
*/
|
||||
- (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
|
||||
[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;
|
||||
}
|
||||
|
||||
NSUInteger nodeCount = nodes.count;
|
||||
NSUInteger nodeCount = contexts.count;
|
||||
NSMutableArray<ASCellNode *> *allocatedNodes = [NSMutableArray<ASCellNode *> arrayWithCapacity:nodeCount];
|
||||
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) {
|
||||
NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, indexPaths.count - j);
|
||||
for (NSUInteger j = 0; j < nodeCount; j += kASDataControllerSizingCountPerProcessor) {
|
||||
NSInteger batchCount = MIN(kASDataControllerSizingCountPerProcessor, nodeCount - j);
|
||||
|
||||
__block NSArray *subarray;
|
||||
// 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_apply(batchCount, queue, ^(size_t i) {
|
||||
unsigned long k = j + i;
|
||||
ASCellNodeBlock cellBlock = nodes[k];
|
||||
ASCellNode *node = cellBlock();
|
||||
ASIndexedNodeContext *context = contexts[k];
|
||||
ASCellNodeBlock nodeBlock = context.nodeBlock;
|
||||
ASCellNode *node = nodeBlock();
|
||||
ASDisplayNodeAssertNotNil(node, @"Node block created nil node");
|
||||
allocatedNodeBuffer[i] = node;
|
||||
if (!node.isNodeLoaded) {
|
||||
nodeBoundSizes[k] = [self constrainedSizeForNodeOfKind:kind atIndexPath:indexPaths[k]];
|
||||
}
|
||||
});
|
||||
subarray = [[NSArray alloc] initWithObjects:allocatedNodeBuffer count:batchCount];
|
||||
|
||||
@ -200,11 +200,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
dispatch_semaphore_signal(sema);
|
||||
});
|
||||
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 {
|
||||
allocationBlock();
|
||||
[_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.
|
||||
// We should already have measured loaded nodes before we left the main thread, using layoutLoadedNodes:ofKind:atIndexPaths:
|
||||
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.
|
||||
dispatch_group_wait(layoutGroup, DISPATCH_TIME_FOREVER);
|
||||
free(nodeBoundSizes);
|
||||
|
||||
|
||||
if (completionBlock) {
|
||||
NSMutableArray *indexPaths = [NSMutableArray arrayWithCapacity:nodeCount];
|
||||
[contexts enumerateObjectsUsingBlock:^(ASIndexedNodeContext * _Nonnull context, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[indexPaths addObject:context.indexPath];
|
||||
}];
|
||||
|
||||
completionBlock(allocatedNodes, indexPaths);
|
||||
}
|
||||
}
|
||||
@ -238,10 +242,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
NSMutableArray *editingNodes = _editingNodes[kind];
|
||||
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) {
|
||||
return;
|
||||
@ -417,9 +422,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
|
||||
[self accessDataSourceSynchronously:synchronously withBlock:^{
|
||||
NSUInteger sectionCount = [_dataSource numberOfSectionsInDataController:self];
|
||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
||||
[self _populateFromEntireDataSourceWithMutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateFromEntireDataSourceWithMutableContexts:contexts];
|
||||
|
||||
// Allow subclasses to perform setup before going into the edit transaction
|
||||
[self prepareForReloadData];
|
||||
@ -445,7 +449,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
|
||||
[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) {
|
||||
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.
|
||||
*/
|
||||
- (void)_populateFromDataSourceWithSectionIndexSet:(NSIndexSet *)indexSet mutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
||||
- (void)_populateFromDataSourceWithSectionIndexSet:(NSIndexSet *)indexSet mutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||
{
|
||||
[indexSet enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
|
||||
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:idx];
|
||||
NSIndexPath *sectionIndex = [[NSIndexPath alloc] initWithIndex:idx];
|
||||
for (NSUInteger i = 0; i < rowNum; i++) {
|
||||
NSIndexPath *indexPath = [sectionIndex indexPathByAddingIndex:i];
|
||||
[indexPaths addObject:indexPath];
|
||||
[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]];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
- (void)_populateFromEntireDataSourceWithMutableNodes:(NSMutableArray *)nodes mutableIndexPaths:(NSMutableArray *)indexPaths
|
||||
- (void)_populateFromEntireDataSourceWithMutableContexts:(NSMutableArray<ASIndexedNodeContext *> *)contexts
|
||||
{
|
||||
NSUInteger sectionNum = [_dataSource numberOfSectionsInDataController:self];
|
||||
for (NSUInteger i = 0; i < sectionNum; i++) {
|
||||
@ -519,8 +526,11 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
NSUInteger rowNum = [_dataSource dataController:self rowsInSection:i];
|
||||
for (NSUInteger j = 0; j < rowNum; j++) {
|
||||
NSIndexPath *indexPath = [sectionIndexPath indexPathByAddingIndex:j];
|
||||
[indexPaths addObject:indexPath];
|
||||
[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]];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -607,9 +617,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
[_editingTransactionQueue waitUntilAllOperationsAreFinished];
|
||||
|
||||
[self accessDataSourceWithBlock:^{
|
||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableContexts:contexts];
|
||||
|
||||
[self prepareForInsertSections:sections];
|
||||
|
||||
@ -623,7 +632,8 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
}
|
||||
|
||||
[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];
|
||||
|
||||
[self accessDataSourceWithBlock:^{
|
||||
NSMutableArray *updatedNodes = [NSMutableArray array];
|
||||
NSMutableArray *updatedIndexPaths = [NSMutableArray array];
|
||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableNodes:updatedNodes mutableIndexPaths:updatedIndexPaths];
|
||||
NSMutableArray<ASIndexedNodeContext *> *contexts = [NSMutableArray array];
|
||||
[self _populateFromDataSourceWithSectionIndexSet:sections mutableContexts:contexts];
|
||||
|
||||
[self prepareForReloadSections:sections];
|
||||
|
||||
@ -674,7 +683,7 @@ static void *kASSizingQueueContext = &kASSizingQueueContext;
|
||||
[self _deleteNodesAtIndexPaths:indexPaths withAnimationOptions:animationOptions];
|
||||
|
||||
// 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:^{
|
||||
// sort indexPath to avoid messing up the index when inserting in several batches
|
||||
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++) {
|
||||
[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:^{
|
||||
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.
|
||||
[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: Shouldn't deletes be sorted in descending order?
|
||||
[indexPaths sortedArrayUsingSelector:@selector(compare:)];
|
||||
|
||||
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:^{
|
||||
LOG(@"Edit Transaction - reloadRows: %@", indexPaths);
|
||||
[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