mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-11 08:50:24 +00:00
Implement node-backing for ASTableView and ASCollectionView, with a strong back-pointer in these cases.
This commit is contained in:
parent
02ab9e230f
commit
44feece701
@ -22,7 +22,7 @@
|
||||
@end
|
||||
|
||||
@interface ASCollectionView ()
|
||||
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
|
||||
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout ownedByNode:(BOOL)ownedByNode;
|
||||
@end
|
||||
|
||||
@implementation ASCollectionNode
|
||||
@ -40,10 +40,19 @@
|
||||
return [self initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
}
|
||||
|
||||
- (instancetype)_initWithCollectionView:(ASCollectionView *)collectionView
|
||||
{
|
||||
if (self = [super initWithViewBlock:^UIView *{ return collectionView; }]) {
|
||||
__unused ASCollectionView *collectionView = [self view];
|
||||
return self;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||
{
|
||||
ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{
|
||||
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout];
|
||||
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout ownedByNode:YES];
|
||||
};
|
||||
|
||||
if (self = [super initWithViewBlock:collectionViewBlock]) {
|
||||
|
||||
@ -22,10 +22,16 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
* Node-based collection view.
|
||||
* Asynchronous UICollectionView with Intelligent Preloading capabilities.
|
||||
*
|
||||
* ASCollectionView is a version of UICollectionView that uses nodes -- specifically, ASCellNode subclasses -- with asynchronous
|
||||
* pre-rendering instead of synchronously loading UICollectionViewCells.
|
||||
* ASCollectionNode is recommended over ASCollectionView. This class exists for adoption convenience.
|
||||
*
|
||||
* ASCollectionView is a true subclass of UICollectionView, meaning it is pointer-compatible
|
||||
* with code that currently uses UICollectionView.
|
||||
*
|
||||
* The main difference is that asyncDataSource expects -nodeForItemAtIndexPath, an ASCellNode, and
|
||||
* the sizeForItemAtIndexPath: method is eliminated (as are the performance problems caused by it).
|
||||
* This is made possible because ASCellNodes can calculate their own size, and preload ahead of time.
|
||||
*/
|
||||
@interface ASCollectionView : UICollectionView
|
||||
|
||||
|
||||
@ -99,6 +99,16 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||
|
||||
// Used only when ASCollectionView is created directly rather than through ASCollectionNode.
|
||||
// We create a node so that logic related to appearance, memory management, etc can be located there
|
||||
// for both the node-based and view-based version of the table.
|
||||
// This also permits sharing logic with ASTableNode, as the superclass is not UIKit-controlled.
|
||||
@property (nonatomic, retain) ASCollectionNode *strongCollectionNode;
|
||||
|
||||
@end
|
||||
|
||||
@interface ASCollectionNode ()
|
||||
- (instancetype)_initWithCollectionView:(ASCollectionView *)collectionView;
|
||||
@end
|
||||
|
||||
@implementation ASCollectionView
|
||||
@ -108,26 +118,31 @@ static NSString * const kCellReuseIdentifier = @"_ASCollectionViewCell";
|
||||
|
||||
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout
|
||||
{
|
||||
return [self initWithFrame:CGRectZero collectionViewLayout:layout];
|
||||
return [self _initWithFrame:CGRectZero collectionViewLayout:layout ownedByNode:NO];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||
{
|
||||
ASCollectionNode *collectionNode = [[ASCollectionNode alloc] initWithFrame:frame collectionViewLayout:layout];
|
||||
return collectionNode.view;
|
||||
return [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO];
|
||||
}
|
||||
|
||||
// FIXME: This method is deprecated and will probably be removed in or shortly after 2.0.
|
||||
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
return [self initWithFrame:frame collectionViewLayout:layout];
|
||||
return [self _initWithFrame:frame collectionViewLayout:layout ownedByNode:NO];
|
||||
}
|
||||
|
||||
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
|
||||
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout ownedByNode:(BOOL)ownedByNode
|
||||
{
|
||||
if (!(self = [super initWithFrame:frame collectionViewLayout:layout]))
|
||||
return nil;
|
||||
|
||||
if (!ownedByNode) {
|
||||
// See commentary at the definition of .strongCollectionNode for why we create an ASCollectionNode.
|
||||
ASCollectionNode *collectionNode = [[ASCollectionNode alloc] _initWithCollectionView:self];
|
||||
self.strongCollectionNode = collectionNode;
|
||||
}
|
||||
|
||||
_layoutController = [[ASCollectionViewLayoutController alloc] initWithCollectionView:self];
|
||||
|
||||
_rangeController = [[ASRangeController alloc] init];
|
||||
|
||||
@ -205,6 +205,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*/
|
||||
@property (nonatomic, readonly) ASInterfaceState interfaceState;
|
||||
|
||||
|
||||
/** @name Managing dimensions */
|
||||
|
||||
/**
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
#import "ASFlowLayoutController.h"
|
||||
#import "ASTableNode.h"
|
||||
#import "ASTableViewInternal.h"
|
||||
#import "ASDisplayNode+Subclasses.h"
|
||||
|
||||
@interface _ASTablePendingState : NSObject
|
||||
@ -28,11 +28,22 @@
|
||||
|
||||
@implementation ASTableNode
|
||||
|
||||
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
|
||||
- (instancetype)_initWithTableView:(ASTableView *)tableView
|
||||
{
|
||||
if (self = [super initWithViewBlock:^UIView *{ return [[ASTableView alloc] _initWithFrame:CGRectZero
|
||||
style:style
|
||||
dataControllerClass:dataControllerClass]; }]) {
|
||||
if (self = [super initWithViewBlock:^UIView *{ return tableView; }]) {
|
||||
__unused ASTableView *tableView = [self view];
|
||||
return self;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
|
||||
{
|
||||
ASDisplayNodeViewBlock tableViewBlock = ^UIView *{
|
||||
return [[ASTableView alloc] _initWithFrame:frame style:style dataControllerClass:dataControllerClass ownedByNode:YES];
|
||||
};
|
||||
|
||||
if (self = [super initWithViewBlock:tableViewBlock]) {
|
||||
return self;
|
||||
}
|
||||
return nil;
|
||||
@ -40,12 +51,12 @@
|
||||
|
||||
- (instancetype)initWithStyle:(UITableViewStyle)style
|
||||
{
|
||||
return [self _initWithStyle:style dataControllerClass:nil];
|
||||
return [self _initWithFrame:CGRectZero style:style dataControllerClass:nil];
|
||||
}
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self _initWithStyle:UITableViewStylePlain dataControllerClass:nil];
|
||||
return [self _initWithFrame:CGRectZero style:UITableViewStylePlain dataControllerClass:nil];
|
||||
}
|
||||
|
||||
- (void)didLoad
|
||||
|
||||
@ -19,10 +19,16 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
@protocol ASTableDelegate;
|
||||
|
||||
/**
|
||||
* Node-based table view.
|
||||
* Asynchronous UITableView with Intelligent Preloading capabilities.
|
||||
*
|
||||
* ASTableView is a version of UITableView that uses nodes -- specifically, ASCellNode subclasses -- with asynchronous
|
||||
* pre-rendering instead of synchronously loading UITableViewCells.
|
||||
* ASTableNode is recommended over ASTableView. This class is provided for adoption convenience.
|
||||
*
|
||||
* ASTableView is a true subclass of UITableView, meaning it is pointer-compatible with code that
|
||||
* currently uses UITableView
|
||||
*
|
||||
* The main difference is that asyncDataSource expects -nodeForRowAtIndexPath, an ASCellNode, and
|
||||
* the heightForRowAtIndexPath: method is eliminated (as are the performance problems caused by it).
|
||||
* This is made possible because ASCellNodes can calculate their own size, and preload ahead of time.
|
||||
*/
|
||||
@interface ASTableView : UITableView
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
#pragma mark ASTableView
|
||||
|
||||
@interface ASTableNode ()
|
||||
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
|
||||
- (instancetype)_initWithTableView:(ASTableView *)tableView;
|
||||
@end
|
||||
|
||||
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor> {
|
||||
@ -110,6 +110,12 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
@property (atomic, assign) BOOL asyncDataSourceLocked;
|
||||
@property (nonatomic, retain, readwrite) ASDataController *dataController;
|
||||
|
||||
// Used only when ASTableView is created directly rather than through ASTableNode.
|
||||
// We create a node so that logic related to appearance, memory management, etc can be located there
|
||||
// for both the node-based and view-based version of the table.
|
||||
// This also permits sharing logic with ASCollectionNode, as the superclass is not UIKit-controlled.
|
||||
@property (nonatomic, retain) ASTableNode *strongTableNode;
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASTableView
|
||||
@ -122,7 +128,7 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
#pragma mark -
|
||||
#pragma mark Lifecycle
|
||||
|
||||
- (void)configureWithDataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetching
|
||||
- (void)configureWithDataControllerClass:(Class)dataControllerClass
|
||||
{
|
||||
_layoutController = [[ASFlowLayoutController alloc] initWithScrollOption:ASFlowLayoutDirectionVertical];
|
||||
|
||||
@ -131,13 +137,13 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
_rangeController.dataSource = self;
|
||||
_rangeController.delegate = self;
|
||||
|
||||
_dataController = [[dataControllerClass alloc] initWithAsyncDataFetching:asyncDataFetching];
|
||||
_dataController = [[dataControllerClass alloc] initWithAsyncDataFetching:NO];
|
||||
_dataController.dataSource = self;
|
||||
_dataController.delegate = _rangeController;
|
||||
|
||||
_layoutController.dataSource = _dataController;
|
||||
|
||||
_asyncDataFetchingEnabled = asyncDataFetching;
|
||||
_asyncDataFetchingEnabled = NO;
|
||||
_asyncDataSourceLocked = NO;
|
||||
|
||||
_leadingScreensForBatching = 1.0;
|
||||
@ -161,32 +167,32 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style
|
||||
{
|
||||
return [self initWithFrame:frame style:style asyncDataFetching:NO];
|
||||
return [self _initWithFrame:frame style:style dataControllerClass:nil ownedByNode:NO];
|
||||
}
|
||||
|
||||
// FIXME: This method is deprecated and will probably be removed in or shortly after 2.0.
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
{
|
||||
return [self initWithFrame:frame style:style dataControllerClass:[self.class dataControllerClass] asyncDataFetching:asyncDataFetchingEnabled];
|
||||
return [self _initWithFrame:frame style:style dataControllerClass:nil ownedByNode:NO];
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass ownedByNode:(BOOL)ownedByNode
|
||||
{
|
||||
// ASTableNode *tableNode = [[ASTableNode alloc] _initWithStyle:style dataControllerClass:dataControllerClass];
|
||||
// tableNode.frame = frame;
|
||||
// return tableNode.view;
|
||||
return [self _initWithFrame:frame style:style dataControllerClass:dataControllerClass];
|
||||
}
|
||||
|
||||
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
|
||||
{
|
||||
if (!(self = [super initWithFrame:frame style:style]))
|
||||
if (!(self = [super initWithFrame:frame style:style])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (!dataControllerClass) {
|
||||
dataControllerClass = [self.class dataControllerClass];
|
||||
}
|
||||
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:NO];
|
||||
|
||||
[self configureWithDataControllerClass:dataControllerClass];
|
||||
|
||||
if (!ownedByNode) {
|
||||
// See commentary at the definition of .strongTableNode for why we create an ASTableNode.
|
||||
ASTableNode *tableNode = [[ASTableNode alloc] _initWithTableView:self];
|
||||
self.strongTableNode = tableNode;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@ -26,6 +26,6 @@
|
||||
*
|
||||
* @param asyncDataFetchingEnabled This option is reserved for future use, and currently a no-op.
|
||||
*/
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled;
|
||||
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass ownedByNode:(BOOL)ownedByNode;
|
||||
|
||||
@end
|
||||
|
||||
@ -55,7 +55,7 @@ NS_ASSUME_NONNULL_BEGIN
|
||||
*
|
||||
* @return a new instance of ASLayoutOptions
|
||||
*/
|
||||
- (instancetype)initWithLayoutable:(nullable id<ASLayoutable>)layoutable NS_DESIGNATED_INITIALIZER;
|
||||
- (instancetype)initWithLayoutable:(id<ASLayoutable>)layoutable;
|
||||
|
||||
/**
|
||||
* Copies the values of layoutOptions into self. This is useful when placing a layoutable inside of another. Consider
|
||||
|
||||
@ -56,10 +56,10 @@ static Class gDefaultLayoutOptionsClass = nil;
|
||||
|
||||
- (instancetype)init
|
||||
{
|
||||
return [self initWithLayoutable:nil];
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (instancetype)initWithLayoutable:(id<ASLayoutable>)layoutable;
|
||||
- (instancetype)initWithLayoutable:(id<ASLayoutable>)layoutable
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
|
||||
@ -160,6 +160,20 @@ typedef NS_OPTIONS(NSUInteger, ASDisplayNodeMethodOverrides)
|
||||
|
||||
@property (nonatomic, assign) CGFloat contentsScaleForDisplay;
|
||||
|
||||
/**
|
||||
* // TODO: NOT YET IMPLEMENTED
|
||||
*
|
||||
* @abstract Prevents interface state changes from affecting the node, until disabled.
|
||||
*
|
||||
* @discussion Useful to avoid flashing after removing a node from the hierarchy and re-adding it.
|
||||
* Removing a node from the hierarchy will cause it to exit the Display state, clearing its contents.
|
||||
* For some animations, it's desirable to be able to remove a node without causing it to re-display.
|
||||
* Once re-enabled, the interface state will be updated to the same value it would have been.
|
||||
*
|
||||
* @see ASInterfaceState
|
||||
*/
|
||||
@property (nonatomic, assign) BOOL interfaceStateSuspended;
|
||||
|
||||
/**
|
||||
* This method has proven helpful in a few rare scenarios, similar to a category extension on UIView,
|
||||
* but it's considered private API for now and its use should not be encouraged.
|
||||
|
||||
@ -37,9 +37,9 @@
|
||||
|
||||
@implementation ASTestTableView
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style asyncDataFetching:(BOOL)asyncDataFetchingEnabled
|
||||
- (instancetype)__initWithFrame:(CGRect)frame style:(UITableViewStyle)style
|
||||
{
|
||||
return [super initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] asyncDataFetching:asyncDataFetchingEnabled];
|
||||
return [super _initWithFrame:frame style:style dataControllerClass:[ASTestDataController class] ownedByNode:NO];
|
||||
}
|
||||
|
||||
- (ASTestDataController *)testDataController
|
||||
@ -124,6 +124,7 @@
|
||||
@end
|
||||
|
||||
@interface ASTableViewTests : XCTestCase
|
||||
@property (atomic, retain) ASTableView *testTableView;
|
||||
@end
|
||||
|
||||
@implementation ASTableViewTests
|
||||
@ -131,7 +132,7 @@
|
||||
// TODO: Convert this to ARC.
|
||||
- (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate
|
||||
{
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectZero style:UITableViewStylePlain];
|
||||
|
||||
__block BOOL tableViewDidDealloc = NO;
|
||||
tableView.willDeallocBlock = ^(ASTableView *v){
|
||||
@ -185,9 +186,8 @@
|
||||
- (void)testReloadData
|
||||
{
|
||||
// Keep the viewport moderately sized so that new cells are loaded on scrolling
|
||||
ASTableView *tableView = [[ASTableView alloc] initWithFrame:CGRectMake(0, 0, 100, 500)
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, 100, 500)
|
||||
style:UITableViewStylePlain];
|
||||
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
|
||||
@ -250,9 +250,8 @@
|
||||
// Any subsequence size change must trigger a relayout.
|
||||
CGSize tableViewFinalSize = CGSizeMake(100, 500);
|
||||
// Width and height are swapped so that a later size change will simulate a rotation
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectMake(0, 0, tableViewFinalSize.height, tableViewFinalSize.width)
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, tableViewFinalSize.height, tableViewFinalSize.width)
|
||||
style:UITableViewStylePlain];
|
||||
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
|
||||
@ -270,9 +269,8 @@
|
||||
// Initial width of the table view is 0. The first size change is part of the initial config.
|
||||
// Any subsequence size change after that must trigger a relayout.
|
||||
CGSize tableViewFinalSize = CGSizeMake(100, 500);
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectZero
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectZero
|
||||
style:UITableViewStylePlain];
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
|
||||
tableView.asyncDelegate = dataSource;
|
||||
@ -292,9 +290,8 @@
|
||||
- (void)testRelayoutVisibleRowsWhenEditingModeIsChanged
|
||||
{
|
||||
CGSize tableViewSize = CGSizeMake(100, 500);
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectMake(0, 0, tableViewSize.width, tableViewSize.height)
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, tableViewSize.width, tableViewSize.height)
|
||||
style:UITableViewStylePlain];
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
|
||||
tableView.asyncDelegate = dataSource;
|
||||
@ -361,9 +358,8 @@
|
||||
- (void)DISABLED_testRelayoutRowsAfterEditingModeIsChangedAndTheyBecomeVisible
|
||||
{
|
||||
CGSize tableViewSize = CGSizeMake(100, 500);
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectMake(0, 0, tableViewSize.width, tableViewSize.height)
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTestTableView *tableView = [[ASTestTableView alloc] __initWithFrame:CGRectMake(0, 0, tableViewSize.width, tableViewSize.height)
|
||||
style:UITableViewStylePlain];
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
|
||||
tableView.asyncDelegate = dataSource;
|
||||
@ -398,9 +394,6 @@
|
||||
style:UITableViewStylePlain
|
||||
asyncDataFetching:YES];
|
||||
ASTableViewFilledDataSource *dataSource = [ASTableViewFilledDataSource new];
|
||||
#if ! __has_feature(objc_arc)
|
||||
#error This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
||||
#endif
|
||||
|
||||
tableView.asyncDelegate = dataSource;
|
||||
tableView.asyncDataSource = dataSource;
|
||||
@ -414,6 +407,7 @@
|
||||
XCTAssertEqual(indexPath.row, reportedIndexPath.row);
|
||||
}
|
||||
}
|
||||
self.testTableView = nil;
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user