Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit a13b36d

Browse files
author
Adlai Holler
authored
Allow UICollectionViewLayout to Provide Layout Inspector, Always Update Delegate (#3003)
* Allow UICollectionViewLayout to give us a layout inspector, always call the didChangeDelegate/didChangeDataSource on binding * Make an assertion * Update the tests * Tests use actual layout inspector * Be more consistent
1 parent 1adfb00 commit a13b36d

8 files changed

Lines changed: 53 additions & 39 deletions

AsyncDisplayKit/ASCollectionView.mm

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -533,19 +533,14 @@ - (void)setCollectionViewLayout:(UICollectionViewLayout *)collectionViewLayout
533533
- (id<ASCollectionViewLayoutInspecting>)layoutInspector
534534
{
535535
if (_layoutInspector == nil) {
536-
UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout;
536+
UICollectionViewLayout *layout = self.collectionViewLayout;
537537
if (layout == nil) {
538538
// Layout hasn't been set yet, we're still init'ing
539539
return nil;
540540
}
541-
542-
if ([layout asdk_isFlowLayout]) {
543-
// Register the default layout inspector delegate for flow layouts only
544-
_defaultLayoutInspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:self flowLayout:layout];
545-
} else {
546-
// Register the default layout inspector delegate for custom collection view layouts
547-
_defaultLayoutInspector = [[ASCollectionViewLayoutInspector alloc] initWithCollectionView:self];
548-
}
541+
542+
_defaultLayoutInspector = [layout asdk_layoutInspector];
543+
ASDisplayNodeAssertNotNil(_defaultLayoutInspector, @"You must not return nil from -asdk_layoutInspector. Return [super asdk_layoutInspector] if you have to! Layout: %@", layout);
549544

550545
// Explicitly call the setter to wire up the _layoutInspectorFlags
551546
self.layoutInspector = _defaultLayoutInspector;
@@ -560,6 +555,13 @@ - (void)setLayoutInspector:(id<ASCollectionViewLayoutInspecting>)layoutInspector
560555

561556
_layoutInspectorFlags.didChangeCollectionViewDataSource = [_layoutInspector respondsToSelector:@selector(didChangeCollectionViewDataSource:)];
562557
_layoutInspectorFlags.didChangeCollectionViewDelegate = [_layoutInspector respondsToSelector:@selector(didChangeCollectionViewDelegate:)];
558+
559+
if (_layoutInspectorFlags.didChangeCollectionViewDataSource) {
560+
[_layoutInspector didChangeCollectionViewDataSource:self.asyncDataSource];
561+
}
562+
if (_layoutInspectorFlags.didChangeCollectionViewDelegate) {
563+
[_layoutInspector didChangeCollectionViewDelegate:self.asyncDelegate];
564+
}
563565
}
564566

565567
- (void)setTuningParameters:(ASRangeTuningParameters)tuningParameters forRangeType:(ASLayoutRangeType)rangeType

AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,12 @@ extern ASSizeRange NodeConstrainedSizeForScrollDirection(ASCollectionView *colle
7272
* A layout inspector for non-flow layouts that returns a constrained size to let the cells layout itself as
7373
* far as possible based on the scrollable direction of the collection view. It throws exceptions for delegate
7474
* methods that are related to supplementary node's management.
75+
*
76+
* @warning This class is not meant to be subclassed and will be restricted in the future.
7577
*/
7678
@interface ASCollectionViewLayoutInspector : NSObject <ASCollectionViewLayoutInspecting>
7779

78-
- (instancetype)init NS_UNAVAILABLE;
79-
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView NS_DESIGNATED_INITIALIZER;
80+
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView ASDISPLAYNODE_DEPRECATED_MSG("Use -init instead.");
8081

8182
@end
8283

AsyncDisplayKit/Details/ASCollectionViewLayoutInspector.m

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,7 @@ @implementation ASCollectionViewLayoutInspector {
3939

4040
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
4141
{
42-
self = [super init];
43-
if (self != nil) {
44-
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
45-
}
46-
return self;
42+
return [self init];
4743
}
4844

4945
#pragma mark ASCollectionViewLayoutInspecting

AsyncDisplayKit/Details/UICollectionViewLayout+ASConvenience.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,21 @@
88
// of patent rights can be found in the PATENTS file in the same directory.
99
//
1010

11-
#import <UIKit/UIKit.h>
11+
#import <UIKit/UICollectionViewLayout.h>
12+
13+
@protocol ASCollectionViewLayoutInspecting;
1214

1315
NS_ASSUME_NONNULL_BEGIN
1416

15-
@interface UICollectionViewLayout (ASConvenience)
17+
@interface UICollectionViewLayout (ASLayoutInspectorProviding)
1618

17-
- (BOOL)asdk_isFlowLayout;
19+
/**
20+
* You can override this method on your @c UICollectionViewLayout subclass to
21+
* return a layout inspector tailored to your layout.
22+
*
23+
* It's fine to return @c self. You must not return @c nil.
24+
*/
25+
- (id<ASCollectionViewLayoutInspecting>)asdk_layoutInspector;
1826

1927
@end
2028

AsyncDisplayKit/Details/UICollectionViewLayout+ASConvenience.m

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@
1010

1111
#import <AsyncDisplayKit/UICollectionViewLayout+ASConvenience.h>
1212

13-
@implementation UICollectionViewLayout (ASConvenience)
13+
#import <UIKit/UICollectionViewFlowLayout.h>
1414

15-
- (BOOL)asdk_isFlowLayout
15+
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
16+
17+
@implementation UICollectionViewLayout (ASLayoutInspectorProviding)
18+
19+
- (id<ASCollectionViewLayoutInspecting>)asdk_layoutInspector
1620
{
17-
return [self isKindOfClass:[UICollectionViewFlowLayout class]];
21+
UICollectionViewFlowLayout *flow = ASDynamicCast(self, UICollectionViewFlowLayout);
22+
if (flow != nil) {
23+
return [[ASCollectionViewFlowLayoutInspector alloc] initWithFlowLayout:flow];
24+
} else {
25+
return [[ASCollectionViewLayoutInspector alloc] init];
26+
}
1827
}
1928

2029
@end

AsyncDisplayKit/Private/ASCollectionViewFlowLayoutInspector.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ AS_SUBCLASSING_RESTRICTED
2424
@property (nonatomic, weak, readonly) UICollectionViewFlowLayout *layout;
2525

2626
- (instancetype)init NS_UNAVAILABLE;
27-
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView flowLayout:(UICollectionViewFlowLayout *)flowLayout NS_DESIGNATED_INITIALIZER;
27+
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout NS_DESIGNATED_INITIALIZER;
2828

2929
@end
3030

AsyncDisplayKit/Private/ASCollectionViewFlowLayoutInspector.m

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,12 @@ @implementation ASCollectionViewFlowLayoutInspector {
3636

3737
#pragma mark Lifecycle
3838

39-
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView flowLayout:(UICollectionViewFlowLayout *)flowLayout;
39+
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout;
4040
{
41-
NSParameterAssert(collectionView);
4241
NSParameterAssert(flowLayout);
4342

4443
self = [super init];
4544
if (self != nil) {
46-
[self didChangeCollectionViewDelegate:collectionView.asyncDelegate];
4745
_layout = flowLayout;
4846
}
4947
return self;

AsyncDisplayKitTests/ASCollectionViewFlowLayoutInspectorTests.m

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ - (void)testThatItReturnsAVerticalConstrainedSizeFromTheHeaderDelegateImplementa
143143
collectionView.asyncDataSource = dataSource;
144144
collectionView.asyncDelegate = delegate;
145145

146-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
146+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
147147
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
148148
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
149149

@@ -166,7 +166,7 @@ - (void)testThatItReturnsAVerticalConstrainedSizeFromTheFooterDelegateImplementa
166166
collectionView.asyncDataSource = dataSource;
167167
collectionView.asyncDelegate = delegate;
168168

169-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
169+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
170170
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
171171
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
172172
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
@@ -189,7 +189,7 @@ - (void)testThatItReturnsAVerticalConstrainedSizeFromTheHeaderProperty
189189
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
190190
collectionView.asyncDataSource = dataSource;
191191

192-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
192+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
193193
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
194194
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
195195
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
@@ -210,7 +210,7 @@ - (void)testThatItReturnsAVerticalConstrainedSizeFromTheFooterProperty
210210
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
211211
collectionView.asyncDataSource = dataSource;
212212

213-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
213+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
214214
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
215215
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(collectionView.bounds.size.width, 125.0));
216216
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
@@ -234,7 +234,7 @@ - (void)testThatItReturnsAHorizontalConstrainedSizeFromTheHeaderDelegateImplemen
234234
collectionView.asyncDataSource = dataSource;
235235
collectionView.asyncDelegate = delegate;
236236

237-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
237+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
238238
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
239239
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
240240
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
@@ -256,7 +256,7 @@ - (void)testThatItReturnsAHorizontalConstrainedSizeFromTheFooterDelegateImplemen
256256
collectionView.asyncDataSource = dataSource;
257257
collectionView.asyncDelegate = delegate;
258258

259-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
259+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
260260
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
261261
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
262262
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the values returned in the delegate implementation");
@@ -279,7 +279,7 @@ - (void)testThatItReturnsAHorizontalConstrainedSizeFromTheHeaderProperty
279279
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
280280
collectionView.asyncDataSource = dataSource;
281281

282-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
282+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
283283
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionHeader atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
284284
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.width));
285285
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
@@ -300,7 +300,7 @@ - (void)testThatItReturnsAHorizontalConstrainedSizeFromTheFooterProperty
300300
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:rect collectionViewLayout:layout];
301301
collectionView.asyncDataSource = dataSource;
302302

303-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
303+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
304304
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
305305
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeMake(125.0, collectionView.bounds.size.height));
306306
ASXCTAssertEqualSizeRanges(size, sizeCompare, @"should have a size constrained by the size set on the layout");
@@ -317,7 +317,7 @@ - (void)testThatItReturnsZeroSizeWhenNoReferenceSizeIsImplemented
317317
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
318318
collectionView.asyncDataSource = dataSource;
319319
collectionView.asyncDelegate = delegate;
320-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
320+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
321321
ASSizeRange size = [inspector collectionView:collectionView constrainedSizeForSupplementaryNodeOfKind:UICollectionElementKindSectionFooter atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]];
322322
ASSizeRange sizeCompare = ASSizeRangeMake(CGSizeZero, CGSizeZero);
323323
XCTAssert(CGSizeEqualToSize(size.min, sizeCompare.min) && CGSizeEqualToSize(size.max, sizeCompare.max), @"should have a zero size");
@@ -336,7 +336,7 @@ - (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheDelegate
336336
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
337337
collectionView.asyncDataSource = dataSource;
338338
collectionView.asyncDelegate = delegate;
339-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
339+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
340340
NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionHeader inSection:0];
341341
XCTAssert(count == 1, @"should have a header supplementary view");
342342

@@ -353,7 +353,7 @@ - (void)testThatItReturnsOneWhenAValidSizeIsImplementedOnTheLayout
353353
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
354354
collectionView.asyncDataSource = dataSource;
355355
collectionView.asyncDelegate = delegate;
356-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
356+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
357357
NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionFooter inSection:0];
358358
XCTAssert(count == 1, @"should have a footer supplementary view");
359359

@@ -369,7 +369,7 @@ - (void)testThatItReturnsNoneWhenNoReferenceSizeIsImplemented
369369
ASCollectionView *collectionView = [[ASCollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
370370
collectionView.asyncDataSource = dataSource;
371371
collectionView.asyncDelegate = delegate;
372-
ASCollectionViewFlowLayoutInspector *inspector = [[ASCollectionViewFlowLayoutInspector alloc] initWithCollectionView:collectionView flowLayout:layout];
372+
ASCollectionViewFlowLayoutInspector *inspector = ASDynamicCast(collectionView.layoutInspector, ASCollectionViewFlowLayoutInspector);
373373
NSUInteger count = [inspector collectionView:collectionView supplementaryNodesOfKind:UICollectionElementKindSectionFooter inSection:0];
374374
XCTAssert(count == 0, @"should not have a footer supplementary view");
375375

@@ -393,7 +393,7 @@ - (void)testThatItThrowsIfNodeConstrainedSizeIsImplementedOnDataSourceButNotOnDe
393393
id delegate = [InspectorTestDataSourceDelegateWithoutNodeConstrainedSize new];
394394
node.delegate = delegate;
395395

396-
ASCollectionViewLayoutInspector *inspector = [[ASCollectionViewLayoutInspector alloc] initWithCollectionView:collectionView];
396+
ASCollectionViewLayoutInspector *inspector = [[ASCollectionViewLayoutInspector alloc] init];
397397

398398
collectionView.layoutInspector = inspector;
399399
XCTAssertThrows([inspector collectionView:collectionView constrainedSizeForNodeAtIndexPath:indexPath]);

0 commit comments

Comments
 (0)