From 12c67e708a1ebaad3810ec3064ce42bbe8290fc2 Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 5 Jun 2017 19:27:23 -0700 Subject: [PATCH 1/4] [ASCollectionView] synchronous mode --- Source/ASCollectionNode+Beta.h | 17 +++++++++++++++++ Source/ASCollectionNode.mm | 10 ++++++++++ Source/ASCollectionView.mm | 10 ++++++++++ Source/Details/ASCollectionInternal.h | 5 +++++ Source/Details/ASDataController.h | 5 +++++ Source/Details/ASDataController.mm | 4 ++++ 6 files changed, 51 insertions(+) diff --git a/Source/ASCollectionNode+Beta.h b/Source/ASCollectionNode+Beta.h index b23f8d8b3..74625c75d 100644 --- a/Source/ASCollectionNode+Beta.h +++ b/Source/ASCollectionNode+Beta.h @@ -40,6 +40,23 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, weak) id batchFetchingDelegate; +/** + * When this mode is enabled, ASCollectionView matches the timing of UICollectionView as closely as possible, + * ensuring that all reload and edit operations are performed on the main thread as blocking calls. + * + * This mode is useful for applications that are debugging issues with their collection view implementation. + * In particular, some applications do not properly conform to the API requirement of UICollectionView, and these + * applications may experience difficulties with ASCollectionView. Providing this mode allows for developers to + * work towards resolving technical debt in their collection view data source, while ramping up asynchronous + * collection layout. + * + * NOTE: Because this mode results in expensive operations like cell layout being performed on the main thread, + * it should be used as a tool to resolve data source conformance issues with Apple collection view API. + * + * @default defaults to NO. + */ +@property (nonatomic, assign) BOOL usesSynchronousDataLoading; + - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; - (instancetype)initWithLayoutDelegate:(id)layoutDelegate layoutFacilitator:(nullable id)layoutFacilitator; diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 1c64f719e..4936d92cd 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -464,6 +464,16 @@ - (void)setBatchFetchingDelegate:(id)batchFetchingDeleg return _batchFetchingDelegate; } +- (BOOL)usesSynchronousDataLoading +{ + return self.view.usesSynchronousDataLoading; +} + +- (void)setUsesSynchronousDataLoading:(BOOL)usesSynchronousDataLoading +{ + self.view.usesSynchronousDataLoading = usesSynchronousDataLoading; +} + #pragma mark - Range Tuning - (ASRangeTuningParameters)tuningParametersForRangeType:(ASLayoutRangeType)rangeType diff --git a/Source/ASCollectionView.mm b/Source/ASCollectionView.mm index d06769f14..696befb60 100644 --- a/Source/ASCollectionView.mm +++ b/Source/ASCollectionView.mm @@ -767,6 +767,16 @@ - (NSArray *)visibleNodes return visibleNodes; } +- (BOOL)usesSynchronousDataLoading +{ + return self.dataController.usesSynchronousDataLoading; +} + +- (void)setUsesSynchronousDataLoading:(BOOL)usesSynchronousDataLoading +{ + self.dataController.usesSynchronousDataLoading = usesSynchronousDataLoading; +} + #pragma mark Internal - (void)_configureCollectionViewLayout:(nonnull UICollectionViewLayout *)layout diff --git a/Source/Details/ASCollectionInternal.h b/Source/Details/ASCollectionInternal.h index e7e56a1c9..bfab0bf94 100644 --- a/Source/Details/ASCollectionInternal.h +++ b/Source/Details/ASCollectionInternal.h @@ -31,6 +31,11 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, strong, readonly) ASDataController *dataController; @property (nonatomic, strong, readonly) ASRangeController *rangeController; +/** + * @see ASCollectionNode+Beta.h for full documentation. + */ +@property (nonatomic, assign) BOOL usesSynchronousDataLoading; + /** * Attempt to get the view-layer index path for the item with the given index path. * diff --git a/Source/Details/ASDataController.h b/Source/Details/ASDataController.h index 7e35d91b9..fc4d9ee5b 100644 --- a/Source/Details/ASDataController.h +++ b/Source/Details/ASDataController.h @@ -227,6 +227,11 @@ extern NSString * const ASCollectionInvalidUpdateException; @property (nonatomic, strong, readonly) ASEventLog *eventLog; #endif +/** + * @see ASCollectionNode+Beta.h for full documentation. + */ +@property (nonatomic, assign) BOOL usesSynchronousDataLoading; + /** @name Data Updating */ - (void)updateWithChangeSet:(_ASHierarchyChangeSet *)changeSet; diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 83e69d73f..495ece169 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -582,6 +582,10 @@ - (void)updateWithChangeSet:(_ASHierarchyChangeSet *)changeSet }]; }]; }); + + if (_usesSynchronousDataLoading) { + dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER); + } } /** From 52775ec09987daed365117af28ec7e73dc2b917f Mon Sep 17 00:00:00 2001 From: Hannah Troisi Date: Mon, 5 Jun 2017 19:34:00 -0700 Subject: [PATCH 2/4] add to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d326bdc5b..0c189d3de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## master * Add your own contributions to the next release on the line below this with your name. +- Add a synchronous mode to ASCollectionNode, for colletion view data source debugging. [Hannah Troisi](https://github.com/hannahmbanana) - Fixed an issue where GIFs with placeholders never had their placeholders uncover the GIF. [Garrett Moon](https://github.com/garrettmoon) - [Yoga] Implement ASYogaLayoutSpec, a simplified integration strategy for Yoga-powered layout calculation. [Scott Goodson](https://github.com/appleguy) - Fixed an issue where calls to setNeedsDisplay and setNeedsLayout would stop working on loaded nodes. [Garrett Moon](https://github.com/garrettmoon) From 0b54588f7c3c432e0cb85c97fb83d254a0618213 Mon Sep 17 00:00:00 2001 From: appleguy Date: Tue, 6 Jun 2017 12:41:26 -0700 Subject: [PATCH 3/4] Update ASDataController.mm --- Source/Details/ASDataController.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Details/ASDataController.mm b/Source/Details/ASDataController.mm index 495ece169..da4b5e4bd 100644 --- a/Source/Details/ASDataController.mm +++ b/Source/Details/ASDataController.mm @@ -584,7 +584,7 @@ - (void)updateWithChangeSet:(_ASHierarchyChangeSet *)changeSet }); if (_usesSynchronousDataLoading) { - dispatch_group_wait(_editingTransactionGroup, DISPATCH_TIME_FOREVER); + [self waitUntilAllUpdatesAreCommitted]; } } From 18bb5cc9ebe052eba1b322bb12e09b65df66a351 Mon Sep 17 00:00:00 2001 From: appleguy Date: Tue, 6 Jun 2017 12:45:30 -0700 Subject: [PATCH 4/4] Update ASCollectionNode.mm --- Source/ASCollectionNode.mm | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 4936d92cd..4e3a5e43f 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -45,6 +45,7 @@ @interface _ASCollectionPendingState : NSObject @property (nonatomic, assign) BOOL allowsSelection; // default is YES @property (nonatomic, assign) BOOL allowsMultipleSelection; // default is NO @property (nonatomic, assign) BOOL inverted; //default is NO +@property (nonatomic, assign) BOOL usesSynchronousDataLoading; @property (nonatomic, assign) CGFloat leadingScreensForBatching; @property (weak, nonatomic) id layoutInspector; @end @@ -175,13 +176,14 @@ - (void)didLoad if (_pendingState) { _ASCollectionPendingState *pendingState = _pendingState; - self.pendingState = nil; - view.asyncDelegate = pendingState.delegate; - view.asyncDataSource = pendingState.dataSource; - view.inverted = pendingState.inverted; - view.allowsSelection = pendingState.allowsSelection; - view.allowsMultipleSelection = pendingState.allowsMultipleSelection; - view.layoutInspector = pendingState.layoutInspector; + view.asyncDelegate = pendingState.delegate; + view.asyncDataSource = pendingState.dataSource; + view.inverted = pendingState.inverted; + view.allowsSelection = pendingState.allowsSelection; + view.allowsMultipleSelection = pendingState.allowsMultipleSelection; + view.usesSynchronousDataLoading = pendingState.usesSynchronousDataLoading; + view.layoutInspector = pendingState.layoutInspector; + self.pendingState = nil; if (pendingState.rangeMode != ASLayoutRangeModeUnspecified) { [view.rangeController updateCurrentRangeWithMode:pendingState.rangeMode]; @@ -466,12 +468,20 @@ - (void)setBatchFetchingDelegate:(id)batchFetchingDeleg - (BOOL)usesSynchronousDataLoading { - return self.view.usesSynchronousDataLoading; + if ([self pendingState]) { + return _pendingState.usesSynchronousDataLoading; + } else { + return self.view.usesSynchronousDataLoading; + } } - (void)setUsesSynchronousDataLoading:(BOOL)usesSynchronousDataLoading { - self.view.usesSynchronousDataLoading = usesSynchronousDataLoading; + if ([self pendingState]) { + _pendingState.usesSynchronousDataLoading = usesSynchronousDataLoading; + } else { + self.view.usesSynchronousDataLoading = usesSynchronousDataLoading; + } } #pragma mark - Range Tuning