From 03d9873cb291be32793c7a8bd950e5f7ea64d0fb Mon Sep 17 00:00:00 2001 From: appleguy Date: Tue, 21 Mar 2017 09:54:53 -0700 Subject: [PATCH] [ASCollectionNode] Add .collectionViewClass to ASCollectionNode+Beta. (#3198) Although we may not want to support this property long-term, there are some usages of it that are difficult to avoid. Specifically because the complexity it adds is both low, and contained to a small area of the code that would be easy to remove it, it would be great to support this. The usage relates to apps that require the Interop protocol, and are architected to expect a few methods / protocols being implemented on the UICollectionView class itself. It does not directly override ASCollectionView behaviors. So hypothetically, it would also work if it were possible to set ASCollectionView's superclass. Instead, the app is making its own subclass descend from ASCollectionView and use the interop APIs, even in environments where there are no ASCellNodes ever returned. --- Source/ASCollectionNode+Beta.h | 7 +++++++ Source/ASCollectionNode.mm | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Source/ASCollectionNode+Beta.h b/Source/ASCollectionNode+Beta.h index 63aa089085..788d60fd25 100644 --- a/Source/ASCollectionNode+Beta.h +++ b/Source/ASCollectionNode+Beta.h @@ -16,6 +16,13 @@ NS_ASSUME_NONNULL_BEGIN @interface ASCollectionNode (Beta) +/** + * Allows providing a custom subclass of ASCollectionView to be managed by ASCollectionNode. + * + * @default [ASCollectionView class] is used whenever this property is unset or nil. + */ +@property (strong, nonatomic, nullable) Class collectionViewClass; + - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout layoutFacilitator:(nullable id)layoutFacilitator; - (void)beginUpdates ASDISPLAYNODE_DEPRECATED_MSG("Use -performBatchUpdates:completion: instead."); diff --git a/Source/ASCollectionNode.mm b/Source/ASCollectionNode.mm index 4e5fc30d05..172055ba7b 100644 --- a/Source/ASCollectionNode.mm +++ b/Source/ASCollectionNode.mm @@ -100,6 +100,7 @@ @interface ASCollectionNode () { ASDN::RecursiveMutex _environmentStateLock; + Class _collectionViewClass; } @property (nonatomic) _ASCollectionPendingState *pendingState; @end @@ -108,6 +109,20 @@ #pragma mark Lifecycle +- (Class)collectionViewClass +{ + return _collectionViewClass ? : [ASCollectionView class]; +} + +- (void)setCollectionViewClass:(Class)collectionViewClass +{ + if (_collectionViewClass != collectionViewClass) { + ASDisplayNodeAssert([collectionViewClass isSubclassOfClass:[ASCollectionView class]] || collectionViewClass == Nil, @"ASCollectionNode requires that .collectionViewClass is an ASCollectionView subclass"); + ASDisplayNodeAssert([self isNodeLoaded] == NO, @"ASCollectionNode's .collectionViewClass cannot be changed after the view is loaded"); + _collectionViewClass = collectionViewClass; + } +} + - (instancetype)init { ASDISPLAYNODE_NOT_DESIGNATED_INITIALIZER(); @@ -132,7 +147,7 @@ ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{ // Variable will be unused if event logging is off. __unused __typeof__(self) strongSelf = weakSelf; - return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:layoutFacilitator eventLog:ASDisplayNodeGetEventLog(strongSelf)]; + return [[[strongSelf collectionViewClass] alloc] _initWithFrame:frame collectionViewLayout:layout layoutFacilitator:layoutFacilitator eventLog:ASDisplayNodeGetEventLog(strongSelf)]; }; if (self = [super initWithViewBlock:collectionViewBlock didLoadBlock:nil]) {