@@ -61,12 +61,14 @@ static BOOL _isInterceptedSelector(SEL sel)
6161 */  
6262@interface  _ASCollectionViewProxy  : NSProxy 
6363- (instancetype )initWithTarget : (id <NSObject >)target  interceptor : (ASCollectionView *)interceptor ;
64+ @property  (nonatomic , weak ) id <NSObject > target;
6465@end 
6566
6667@implementation  _ASCollectionViewProxy  {
6768  id <NSObject > __weak _target;
6869  ASCollectionView * __weak _interceptor;
6970}
71+ @synthesize  target = _target;
7072
7173- (instancetype )initWithTarget : (id <NSObject >)target  interceptor : (ASCollectionView *)interceptor 
7274{
@@ -202,6 +204,14 @@ - (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionVi
202204  //  and should not trigger a relayout.
203205  _ignoreMaxSizeChange = CGSizeEqualToSize (_maxSizeForNodesConstrainedSize, CGSizeZero);
204206
207+   //  Set up the delegate / dataSource proxy now, so we recieve key method calls from UITableView even if
208+   //  our owner never sets up asyncDelegate (technically the dataSource is required)
209+   _proxyDelegate = [[_ASCollectionViewProxy alloc ] initWithTarget: [NSNull  null ] interceptor: self ];
210+   super.delegate  = (id <UICollectionViewDelegate>)_proxyDelegate;
211+   
212+   _proxyDataSource = [[_ASCollectionViewProxy alloc ] initWithTarget: [NSNull  null ] interceptor: self ];
213+   super.dataSource  = (id <UICollectionViewDataSource>)_proxyDataSource;
214+ 
205215  self.backgroundColor  = [UIColor whiteColor ];
206216
207217  [self  registerClass: [UICollectionViewCell class ] forCellWithReuseIdentifier: @" _ASCollectionViewCell" 
@@ -252,22 +262,21 @@ - (void)setAsyncDataSource:(id<ASCollectionViewDataSource>)asyncDataSource
252262  //  Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
253263  //  the (common) case of nilling the asyncDataSource in the ViewController's dealloc. In this case our _asyncDataSource
254264  //  will return as nil (ARC magic) even though the _proxyDataSource still exists. It's really important to nil out
255-   //  super.dataSource  in this case because calls to _ASTableViewProxy  will start failing and cause crashes.
265+   //  _proxyDataSource.target  in this case because calls to _ASCollectionViewProxy  will start failing and cause crashes.
256266
257267  if  (asyncDataSource == nil ) {
258-     super. dataSource  = nil ;
268+     _proxyDataSource. target  = nil ;
259269    _asyncDataSource = nil ;
260-     _proxyDataSource = nil ;
261270    _asyncDataSourceImplementsConstrainedSizeForNode = NO ;
262271  } else  {
272+     _proxyDataSource.target  = asyncDataSource;
263273    _asyncDataSource = asyncDataSource;
274+     _asyncDataSourceImplementsConstrainedSizeForNode = ([_asyncDataSource respondsToSelector: @selector (collectionView:constrainedSizeForNodeAtIndexPath: )] ? 1  : 0 );
275+     
264276    //  TODO: Support supplementary views with ASCollectionView.
265277    if  ([_asyncDataSource respondsToSelector: @selector (collectionView:viewForSupplementaryElementOfKind:atIndexPath: )]) {
266278      ASDisplayNodeAssert (NO , @" ASCollectionView is planned to support supplementary views by September 2015.  You can work around this issue by using standard items." 
267279    }
268-     _proxyDataSource = [[_ASCollectionViewProxy alloc ] initWithTarget: _asyncDataSource interceptor: self ];
269-     super.dataSource  = (id <UICollectionViewDataSource>)_proxyDataSource;
270-     _asyncDataSourceImplementsConstrainedSizeForNode = ([_asyncDataSource respondsToSelector: @selector (collectionView:constrainedSizeForNodeAtIndexPath: )] ? 1  : 0 );
271280  }
272281}
273282
@@ -276,19 +285,17 @@ - (void)setAsyncDelegate:(id<ASCollectionViewDelegate>)asyncDelegate
276285  //  Note: It's common to check if the value hasn't changed and short-circuit but we aren't doing that here to handle
277286  //  the (common) case of nilling the asyncDelegate in the ViewController's dealloc. In this case our _asyncDelegate
278287  //  will return as nil (ARC magic) even though the _proxyDelegate still exists. It's really important to nil out
279-   //  super.delegate  in this case because calls to _ASTableViewProxy  will start failing and cause crashes.
288+   //  _proxyDelegate.target  in this case because calls to _ASCollectionViewProxy  will start failing and cause crashes.
280289
281290  if  (asyncDelegate == nil ) {
282291    //  order is important here, the delegate must be callable while nilling super.delegate to avoid random crashes
283292    //  in UIScrollViewAccessibility.
284-     super. delegate  = nil ;
293+     _proxyDelegate. target  = nil ;
285294    _asyncDelegate = nil ;
286-     _proxyDelegate = nil ;
287295    _asyncDelegateImplementsInsetSection = NO ;
288296  } else  {
297+     _proxyDelegate.target  = asyncDelegate;
289298    _asyncDelegate = asyncDelegate;
290-     _proxyDelegate = [[_ASCollectionViewProxy alloc ] initWithTarget: _asyncDelegate interceptor: self ];
291-     super.delegate  = (id <UICollectionViewDelegate>)_proxyDelegate;
292299    _asyncDelegateImplementsInsetSection = ([_asyncDelegate respondsToSelector: @selector (collectionView:layout:insetForSectionAtIndex: )] ? 1  : 0 );
293300  }
294301}
0 commit comments