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

Commit 1ec1957

Browse files
committed
Merge pull request #990 from facebook/ASPagerNodeAndCollectionAndTable
[ASPagerNode] New API tweaks. Support setting delegate + dataSource on ASCollectionNode and ASTableNode without triggering view creation.
2 parents 985e47a + 4ca97e2 commit 1ec1957

17 files changed

Lines changed: 352 additions & 105 deletions

AsyncDisplayKit.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@
242242
34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */; };
243243
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */; };
244244
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */; };
245-
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
245+
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; };
246246
430E7C8F1B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
247247
430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
248248
430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */; };

AsyncDisplayKit/ASCollectionNode.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
1818
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
1919

20+
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
21+
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
22+
2023
@property (nonatomic, readonly) ASCollectionView *view;
2124

2225
/**

AsyncDisplayKit/ASCollectionNode.m

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,19 @@
99
#import "ASCollectionNode.h"
1010
#import "ASDisplayNode+Subclasses.h"
1111

12-
@interface ASCollectionView (Internal)
12+
@interface _ASCollectionPendingState : NSObject
13+
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
14+
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
15+
@end
16+
17+
@implementation _ASCollectionPendingState
18+
@end
19+
20+
@interface ASCollectionNode ()
21+
@property (nonatomic) _ASCollectionPendingState *pendingState;
22+
@end
23+
24+
@interface ASCollectionView ()
1325
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
1426
@end
1527

@@ -29,12 +41,77 @@ - (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
2941

3042
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
3143
{
32-
if (self = [super initWithViewBlock:^UIView *{ return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout]; }]) {
44+
ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{
45+
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout];
46+
};
47+
48+
if (self = [super initWithViewBlock:collectionViewBlock]) {
3349
return self;
3450
}
3551
return nil;
3652
}
3753

54+
- (void)didLoad
55+
{
56+
[super didLoad];
57+
58+
if (_pendingState) {
59+
_ASCollectionPendingState *pendingState = _pendingState;
60+
self.pendingState = nil;
61+
62+
ASCollectionView *view = self.view;
63+
view.asyncDelegate = pendingState.delegate;
64+
view.asyncDataSource = pendingState.dataSource;
65+
}
66+
}
67+
68+
- (_ASCollectionPendingState *)pendingState
69+
{
70+
if (!_pendingState && ![self isNodeLoaded]) {
71+
self.pendingState = [[_ASCollectionPendingState alloc] init];
72+
}
73+
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASCollectionNode should not have a pendingState once it is loaded");
74+
return _pendingState;
75+
}
76+
77+
- (void)setDelegate:(id <ASCollectionDelegate>)delegate
78+
{
79+
if ([self pendingState]) {
80+
_pendingState.delegate = delegate;
81+
} else {
82+
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
83+
self.view.asyncDelegate = delegate;
84+
}
85+
}
86+
87+
- (id <ASCollectionDelegate>)delegate
88+
{
89+
if ([self pendingState]) {
90+
return _pendingState.delegate;
91+
} else {
92+
return self.view.asyncDelegate;
93+
}
94+
}
95+
96+
- (void)setDataSource:(id <ASCollectionDataSource>)dataSource
97+
{
98+
if ([self pendingState]) {
99+
_pendingState.dataSource = dataSource;
100+
} else {
101+
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
102+
self.view.asyncDataSource = dataSource;
103+
}
104+
}
105+
106+
- (id <ASCollectionDataSource>)dataSource
107+
{
108+
if ([self pendingState]) {
109+
return _pendingState.dataSource;
110+
} else {
111+
return self.view.asyncDataSource;
112+
}
113+
}
114+
38115
- (ASCollectionView *)view
39116
{
40117
return (ASCollectionView *)[super view];

AsyncDisplayKit/ASCollectionView.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
1616

1717
@class ASCellNode;
18-
@protocol ASCollectionViewDataSource;
19-
@protocol ASCollectionViewDelegate;
18+
@protocol ASCollectionDataSource;
19+
@protocol ASCollectionDelegate;
2020
@protocol ASCollectionViewLayoutInspecting;
2121

2222
/**
@@ -35,8 +35,8 @@
3535
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
3636
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
3737

38-
@property (nonatomic, weak) id<ASCollectionViewDataSource> asyncDataSource;
39-
@property (nonatomic, weak) id<ASCollectionViewDelegate> asyncDelegate; // must not be nil
38+
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate;
39+
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource;
4040

4141
/**
4242
* Tuning parameters for a range type.
@@ -286,7 +286,8 @@
286286
/**
287287
* This is a node-based UICollectionViewDataSource.
288288
*/
289-
@protocol ASCollectionViewDataSource <ASCommonCollectionViewDataSource, NSObject>
289+
#define ASCollectionViewDataSource ASCollectionDataSource
290+
@protocol ASCollectionDataSource <ASCommonCollectionViewDataSource, NSObject>
290291

291292
/**
292293
* Similar to -collectionView:cellForItemAtIndexPath:.
@@ -347,7 +348,8 @@
347348
/**
348349
* This is a node-based UICollectionViewDelegate.
349350
*/
350-
@protocol ASCollectionViewDelegate <ASCommonCollectionViewDelegate, NSObject>
351+
#define ASCollectionViewDelegate ASCollectionDelegate
352+
@protocol ASCollectionDelegate <ASCommonCollectionViewDelegate, NSObject>
351353

352354
@optional
353355

AsyncDisplayKit/ASPagerNode.h

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,35 @@
88

99
#import <AsyncDisplayKit/ASCollectionNode.h>
1010

11-
@protocol ASPagerNodeDataSource;
11+
@class ASPagerNode;
12+
@protocol ASPagerNodeDataSource <NSObject>
13+
// This method replaces -collectionView:numberOfItemsInSection:
14+
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
15+
16+
// This method replaces -collectionView:nodeForItemAtIndexPath:
17+
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
18+
@end
1219

1320
@interface ASPagerNode : ASCollectionNode
1421

15-
@property (weak, nonatomic) id<ASPagerNodeDataSource> dataSource;
22+
// Configures a default horizontal, paging flow layout with 0 inter-item spacing.
23+
- (instancetype)init;
1624

17-
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
25+
// Initializer with custom-configured flow layout properties.
26+
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout;
1827

19-
@end
28+
// The underlying ASCollectionView object.
29+
- (ASCollectionView *)collectionView;
2030

21-
@protocol ASPagerNodeDataSource <NSObject>
31+
// Delegate is optional, and uses the same protocol as ASCollectionNode.
32+
// This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
33+
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
2234

23-
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
35+
// Data Source is required, and uses a different protocol from ASCollectionNode.
36+
- (void)setDataSource:(id <ASPagerNodeDataSource>)dataSource;
37+
- (id <ASPagerNodeDataSource>)dataSource;
2438

25-
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
39+
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
40+
41+
@end
2642

27-
@end

AsyncDisplayKit/ASPagerNode.m

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,20 @@
77
//
88

99
#import "ASPagerNode.h"
10+
#import "ASDelegateProxy.h"
1011

1112
#import <AsyncDisplayKit/AsyncDisplayKit.h>
1213

13-
@interface ASPagerNode () <ASCollectionViewDataSource, ASCollectionViewDelegateFlowLayout> {
14+
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor> {
1415
UICollectionViewFlowLayout *_flowLayout;
16+
ASPagerNodeProxy *_proxy;
17+
id <ASPagerNodeDataSource> _pagerDataSource;
1518
}
1619

1720
@end
1821

1922
@implementation ASPagerNode
23+
@dynamic delegate;
2024

2125
- (instancetype)init
2226
{
@@ -25,24 +29,55 @@ - (instancetype)init
2529
flowLayout.minimumInteritemSpacing = 0;
2630
flowLayout.minimumLineSpacing = 0;
2731

32+
return [self initWithFlowLayout:flowLayout];
33+
}
34+
35+
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout
36+
{
2837
self = [super initWithCollectionViewLayout:flowLayout];
2938
if (self != nil) {
3039
_flowLayout = flowLayout;
3140
}
3241
return self;
3342
}
3443

44+
- (ASCollectionView *)collectionView
45+
{
46+
return self.view;
47+
}
48+
49+
- (void)setDataSource:(id <ASPagerNodeDataSource>)pagerDataSource
50+
{
51+
if (pagerDataSource != _pagerDataSource) {
52+
_pagerDataSource = pagerDataSource;
53+
_proxy = pagerDataSource ? [[ASPagerNodeProxy alloc] initWithTarget:pagerDataSource interceptor:self] : nil;
54+
super.dataSource = (id <ASCollectionDataSource>)_proxy;
55+
}
56+
}
57+
58+
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
59+
{
60+
[self setDataSource:nil];
61+
}
62+
63+
- (id <ASPagerNodeDataSource>)dataSource
64+
{
65+
return _pagerDataSource;
66+
}
67+
3568
- (void)didLoad
3669
{
3770
[super didLoad];
3871

39-
self.view.asyncDataSource = self;
40-
self.view.asyncDelegate = self;
72+
ASCollectionView *cv = self.view;
73+
cv.asyncDataSource = self;
74+
cv.asyncDelegate = self;
4175

42-
self.view.pagingEnabled = YES;
43-
self.view.allowsSelection = NO;
44-
self.view.showsVerticalScrollIndicator = NO;
45-
self.view.showsHorizontalScrollIndicator = NO;
76+
cv.pagingEnabled = YES;
77+
cv.allowsSelection = NO;
78+
cv.showsVerticalScrollIndicator = NO;
79+
cv.showsHorizontalScrollIndicator = NO;
80+
cv.scrollsToTop = NO;
4681

4782
ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 2.0, .trailingBufferScreenfuls = 2.0 };
4883
ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 };
@@ -62,14 +97,14 @@ - (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated
6297

6398
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
6499
{
65-
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
66-
return [self.dataSource pagerNode:self nodeAtIndex:indexPath.item];
100+
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
101+
return [_pagerDataSource pagerNode:self nodeAtIndex:indexPath.item];
67102
}
68103

69104
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
70105
{
71-
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
72-
return [self.dataSource numberOfPagesInPagerNode:self];
106+
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
107+
return [_pagerDataSource numberOfPagesInPagerNode:self];
73108
}
74109

75110
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath

AsyncDisplayKit/ASTableNode.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,13 @@
1414
*/
1515
@interface ASTableNode : ASDisplayNode
1616

17-
- (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
17+
- (instancetype)init; // UITableViewStylePlain
18+
- (instancetype)initWithStyle:(UITableViewStyle)style;
1819

1920
@property (nonatomic, readonly) ASTableView *view;
2021

22+
// These properties can be set without triggering the view to be created, so it's fine to set them in -init.
23+
@property (weak, nonatomic) id <ASTableDelegate> delegate;
24+
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
25+
2126
@end

0 commit comments

Comments
 (0)