Merge pull request #990 from facebook/ASPagerNodeAndCollectionAndTable

[ASPagerNode] New API tweaks.  Support setting delegate + dataSource on ASCollectionNode and ASTableNode without triggering view creation.
This commit is contained in:
appleguy
2015-12-24 23:53:11 -08:00
17 changed files with 352 additions and 105 deletions

View File

@@ -242,7 +242,7 @@
34EFC7771B701D2D00AD841F /* ASStackUnpositionedLayout.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED491B17847A00DA7C62 /* ASStackUnpositionedLayout.h */; };
34EFC7781B701D3100AD841F /* ASStackUnpositionedLayout.mm in Sources */ = {isa = PBXBuildFile; fileRef = ACF6ED4A1B17847A00DA7C62 /* ASStackUnpositionedLayout.mm */; };
34EFC7791B701D3600AD841F /* ASLayoutSpecUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = ACF6ED451B17847A00DA7C62 /* ASLayoutSpecUtilities.h */; };
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
3C9C128519E616EF00E942A0 /* ASTableViewTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 3C9C128419E616EF00E942A0 /* ASTableViewTests.m */; };
430E7C8F1B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
430E7C901B4C23F100697A4C /* ASIndexPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 430E7C8D1B4C23F100697A4C /* ASIndexPath.h */; settings = {ATTRIBUTES = (Public, ); }; };
430E7C911B4C23F100697A4C /* ASIndexPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 430E7C8E1B4C23F100697A4C /* ASIndexPath.m */; };

View File

@@ -17,6 +17,9 @@
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
@property (nonatomic, readonly) ASCollectionView *view;
/**

View File

@@ -9,7 +9,19 @@
#import "ASCollectionNode.h"
#import "ASDisplayNode+Subclasses.h"
@interface ASCollectionView (Internal)
@interface _ASCollectionPendingState : NSObject
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
@property (weak, nonatomic) id <ASCollectionDataSource> dataSource;
@end
@implementation _ASCollectionPendingState
@end
@interface ASCollectionNode ()
@property (nonatomic) _ASCollectionPendingState *pendingState;
@end
@interface ASCollectionView ()
- (instancetype)_initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@end
@@ -29,12 +41,77 @@
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout
{
if (self = [super initWithViewBlock:^UIView *{ return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout]; }]) {
ASDisplayNodeViewBlock collectionViewBlock = ^UIView *{
return [[ASCollectionView alloc] _initWithFrame:frame collectionViewLayout:layout];
};
if (self = [super initWithViewBlock:collectionViewBlock]) {
return self;
}
return nil;
}
- (void)didLoad
{
[super didLoad];
if (_pendingState) {
_ASCollectionPendingState *pendingState = _pendingState;
self.pendingState = nil;
ASCollectionView *view = self.view;
view.asyncDelegate = pendingState.delegate;
view.asyncDataSource = pendingState.dataSource;
}
}
- (_ASCollectionPendingState *)pendingState
{
if (!_pendingState && ![self isNodeLoaded]) {
self.pendingState = [[_ASCollectionPendingState alloc] init];
}
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASCollectionNode should not have a pendingState once it is loaded");
return _pendingState;
}
- (void)setDelegate:(id <ASCollectionDelegate>)delegate
{
if ([self pendingState]) {
_pendingState.delegate = delegate;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
self.view.asyncDelegate = delegate;
}
}
- (id <ASCollectionDelegate>)delegate
{
if ([self pendingState]) {
return _pendingState.delegate;
} else {
return self.view.asyncDelegate;
}
}
- (void)setDataSource:(id <ASCollectionDataSource>)dataSource
{
if ([self pendingState]) {
_pendingState.dataSource = dataSource;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASCollectionNode should be loaded if pendingState doesn't exist");
self.view.asyncDataSource = dataSource;
}
}
- (id <ASCollectionDataSource>)dataSource
{
if ([self pendingState]) {
return _pendingState.dataSource;
} else {
return self.view.asyncDataSource;
}
}
- (ASCollectionView *)view
{
return (ASCollectionView *)[super view];

View File

@@ -15,8 +15,8 @@
#import <AsyncDisplayKit/ASCollectionViewFlowLayoutInspector.h>
@class ASCellNode;
@protocol ASCollectionViewDataSource;
@protocol ASCollectionViewDelegate;
@protocol ASCollectionDataSource;
@protocol ASCollectionDelegate;
@protocol ASCollectionViewLayoutInspecting;
/**
@@ -35,8 +35,8 @@
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@property (nonatomic, weak) id<ASCollectionViewDataSource> asyncDataSource;
@property (nonatomic, weak) id<ASCollectionViewDelegate> asyncDelegate; // must not be nil
@property (nonatomic, weak) id<ASCollectionDelegate> asyncDelegate;
@property (nonatomic, weak) id<ASCollectionDataSource> asyncDataSource;
/**
* Tuning parameters for a range type.
@@ -286,7 +286,8 @@
/**
* This is a node-based UICollectionViewDataSource.
*/
@protocol ASCollectionViewDataSource <ASCommonCollectionViewDataSource, NSObject>
#define ASCollectionViewDataSource ASCollectionDataSource
@protocol ASCollectionDataSource <ASCommonCollectionViewDataSource, NSObject>
/**
* Similar to -collectionView:cellForItemAtIndexPath:.
@@ -347,7 +348,8 @@
/**
* This is a node-based UICollectionViewDelegate.
*/
@protocol ASCollectionViewDelegate <ASCommonCollectionViewDelegate, NSObject>
#define ASCollectionViewDelegate ASCollectionDelegate
@protocol ASCollectionDelegate <ASCommonCollectionViewDelegate, NSObject>
@optional

View File

@@ -8,20 +8,35 @@
#import <AsyncDisplayKit/ASCollectionNode.h>
@protocol ASPagerNodeDataSource;
@class ASPagerNode;
@protocol ASPagerNodeDataSource <NSObject>
// This method replaces -collectionView:numberOfItemsInSection:
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
// This method replaces -collectionView:nodeForItemAtIndexPath:
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
@end
@interface ASPagerNode : ASCollectionNode
@property (weak, nonatomic) id<ASPagerNodeDataSource> dataSource;
// Configures a default horizontal, paging flow layout with 0 inter-item spacing.
- (instancetype)init;
// Initializer with custom-configured flow layout properties.
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout;
// The underlying ASCollectionView object.
- (ASCollectionView *)collectionView;
// Delegate is optional, and uses the same protocol as ASCollectionNode.
// This includes UIScrollViewDelegate as well as most methods from UICollectionViewDelegate, like willDisplay...
@property (weak, nonatomic) id <ASCollectionDelegate> delegate;
// Data Source is required, and uses a different protocol from ASCollectionNode.
- (void)setDataSource:(id <ASPagerNodeDataSource>)dataSource;
- (id <ASPagerNodeDataSource>)dataSource;
- (void)scrollToPageAtIndex:(NSInteger)index animated:(BOOL)animated;
@end
@protocol ASPagerNodeDataSource <NSObject>
- (NSInteger)numberOfPagesInPagerNode:(ASPagerNode *)pagerNode;
- (ASCellNode *)pagerNode:(ASPagerNode *)pagerNode nodeAtIndex:(NSInteger)index;
@end

View File

@@ -7,16 +7,20 @@
//
#import "ASPagerNode.h"
#import "ASDelegateProxy.h"
#import <AsyncDisplayKit/AsyncDisplayKit.h>
@interface ASPagerNode () <ASCollectionViewDataSource, ASCollectionViewDelegateFlowLayout> {
@interface ASPagerNode () <ASCollectionDataSource, ASCollectionViewDelegateFlowLayout, ASDelegateProxyInterceptor> {
UICollectionViewFlowLayout *_flowLayout;
ASPagerNodeProxy *_proxy;
id <ASPagerNodeDataSource> _pagerDataSource;
}
@end
@implementation ASPagerNode
@dynamic delegate;
- (instancetype)init
{
@@ -25,6 +29,11 @@
flowLayout.minimumInteritemSpacing = 0;
flowLayout.minimumLineSpacing = 0;
return [self initWithFlowLayout:flowLayout];
}
- (instancetype)initWithFlowLayout:(UICollectionViewFlowLayout *)flowLayout
{
self = [super initWithCollectionViewLayout:flowLayout];
if (self != nil) {
_flowLayout = flowLayout;
@@ -32,17 +41,43 @@
return self;
}
- (ASCollectionView *)collectionView
{
return self.view;
}
- (void)setDataSource:(id <ASPagerNodeDataSource>)pagerDataSource
{
if (pagerDataSource != _pagerDataSource) {
_pagerDataSource = pagerDataSource;
_proxy = pagerDataSource ? [[ASPagerNodeProxy alloc] initWithTarget:pagerDataSource interceptor:self] : nil;
super.dataSource = (id <ASCollectionDataSource>)_proxy;
}
}
- (void)proxyTargetHasDeallocated:(ASDelegateProxy *)proxy
{
[self setDataSource:nil];
}
- (id <ASPagerNodeDataSource>)dataSource
{
return _pagerDataSource;
}
- (void)didLoad
{
[super didLoad];
self.view.asyncDataSource = self;
self.view.asyncDelegate = self;
ASCollectionView *cv = self.view;
cv.asyncDataSource = self;
cv.asyncDelegate = self;
self.view.pagingEnabled = YES;
self.view.allowsSelection = NO;
self.view.showsVerticalScrollIndicator = NO;
self.view.showsHorizontalScrollIndicator = NO;
cv.pagingEnabled = YES;
cv.allowsSelection = NO;
cv.showsVerticalScrollIndicator = NO;
cv.showsHorizontalScrollIndicator = NO;
cv.scrollsToTop = NO;
ASRangeTuningParameters preloadParams = { .leadingBufferScreenfuls = 2.0, .trailingBufferScreenfuls = 2.0 };
ASRangeTuningParameters renderParams = { .leadingBufferScreenfuls = 1.0, .trailingBufferScreenfuls = 1.0 };
@@ -62,14 +97,14 @@
- (ASCellNode *)collectionView:(ASCollectionView *)collectionView nodeForItemAtIndexPath:(NSIndexPath *)indexPath
{
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
return [self.dataSource pagerNode:self nodeAtIndex:indexPath.item];
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
return [_pagerDataSource pagerNode:self nodeAtIndex:indexPath.item];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
ASDisplayNodeAssert(self.dataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
return [self.dataSource numberOfPagesInPagerNode:self];
ASDisplayNodeAssert(_pagerDataSource != nil, @"ASPagerNode must have a data source to load paging nodes");
return [_pagerDataSource numberOfPagesInPagerNode:self];
}
- (ASSizeRange)collectionView:(ASCollectionView *)collectionView constrainedSizeForNodeAtIndexPath:(NSIndexPath *)indexPath

View File

@@ -14,8 +14,13 @@
*/
@interface ASTableNode : ASDisplayNode
- (instancetype)initWithStyle:(UITableViewStyle)style NS_DESIGNATED_INITIALIZER;
- (instancetype)init; // UITableViewStylePlain
- (instancetype)initWithStyle:(UITableViewStyle)style;
@property (nonatomic, readonly) ASTableView *view;
// These properties can be set without triggering the view to be created, so it's fine to set them in -init.
@property (weak, nonatomic) id <ASTableDelegate> delegate;
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
@end

View File

@@ -8,18 +8,105 @@
#import "ASTableNode.h"
@interface _ASTablePendingState : NSObject
@property (weak, nonatomic) id <ASTableDelegate> delegate;
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
@end
@implementation _ASTablePendingState
@end
@interface ASTableNode ()
@property (nonatomic) _ASTablePendingState *pendingState;
@end
@interface ASTableView ()
- (instancetype)_initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
@end
@implementation ASTableNode
- (instancetype)initWithStyle:(UITableViewStyle)style
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass
{
if (self = [super initWithViewBlock:^UIView *{
return [[ASTableView alloc] initWithFrame:CGRectZero style:style];
}]) {
if (self = [super initWithViewBlock:^UIView *{ return [[ASTableView alloc] _initWithFrame:CGRectZero
style:style
dataControllerClass:dataControllerClass]; }]) {
return self;
}
return nil;
}
- (instancetype)initWithStyle:(UITableViewStyle)style
{
return [self _initWithStyle:style dataControllerClass:nil];
}
- (instancetype)init
{
return [self _initWithStyle:UITableViewStylePlain dataControllerClass:nil];
}
- (void)didLoad
{
[super didLoad];
if (_pendingState) {
_ASTablePendingState *pendingState = _pendingState;
self.pendingState = nil;
ASTableView *view = self.view;
view.asyncDelegate = pendingState.delegate;
view.asyncDataSource = pendingState.dataSource;
}
}
- (_ASTablePendingState *)pendingState
{
if (!_pendingState && ![self isNodeLoaded]) {
self.pendingState = [[_ASTablePendingState alloc] init];
}
ASDisplayNodeAssert(![self isNodeLoaded] || !_pendingState, @"ASTableNode should not have a pendingState once it is loaded");
return _pendingState;
}
- (void)setDelegate:(id <ASTableDelegate>)delegate
{
if ([self pendingState]) {
_pendingState.delegate = delegate;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.asyncDelegate = delegate;
}
}
- (id <ASTableDelegate>)delegate
{
if ([self pendingState]) {
return _pendingState.delegate;
} else {
return self.view.asyncDelegate;
}
}
- (void)setDataSource:(id <ASTableDataSource>)dataSource
{
if ([self pendingState]) {
_pendingState.dataSource = dataSource;
} else {
ASDisplayNodeAssert([self isNodeLoaded], @"ASTableNode should be loaded if pendingState doesn't exist");
self.view.asyncDataSource = dataSource;
}
}
- (id <ASTableDataSource>)dataSource
{
if ([self pendingState]) {
return _pendingState.dataSource;
} else {
return self.view.asyncDataSource;
}
}
- (ASTableView *)view
{
return (ASTableView *)[super view];

View File

@@ -7,17 +7,14 @@
*/
#import <UIKit/UIKit.h>
#import <AsyncDisplayKit/ASRangeController.h>
#import <AsyncDisplayKit/ASTableViewProtocols.h>
#import <AsyncDisplayKit/ASBaseDefines.h>
#import <AsyncDisplayKit/ASBatchContext.h>
@class ASCellNode;
@protocol ASTableViewDataSource;
@protocol ASTableViewDelegate;
@protocol ASTableDataSource;
@protocol ASTableDelegate;
/**
* Node-based table view.
@@ -27,8 +24,8 @@
*/
@interface ASTableView : UITableView
@property (nonatomic, weak) id<ASTableViewDelegate> asyncDelegate; // must not be nil
@property (nonatomic, weak) id<ASTableViewDataSource> asyncDataSource;
@property (nonatomic, weak) id<ASTableDelegate> asyncDelegate;
@property (nonatomic, weak) id<ASTableDataSource> asyncDataSource;
/**
* Initializer.
@@ -280,7 +277,7 @@
/**
* This is a node-based UITableViewDataSource.
*/
@protocol ASTableViewDataSource <ASCommonTableViewDataSource, NSObject>
@protocol ASTableDataSource <ASCommonTableViewDataSource, NSObject>
/**
* Similar to -tableView:cellForRowAtIndexPath:.
@@ -317,6 +314,8 @@
@end
@protocol ASTableViewDataSource <ASTableDataSource>
@end
/**
* This is a node-based UITableViewDelegate.
@@ -324,7 +323,7 @@
* Note that -tableView:heightForRowAtIndexPath: has been removed; instead, your custom ASCellNode subclasses are
* responsible for deciding their preferred onscreen height in -calculateSizeThatFits:.
*/
@protocol ASTableViewDelegate <ASCommonTableViewDelegate, NSObject>
@protocol ASTableDelegate <ASCommonTableViewDelegate, NSObject>
@optional
@@ -358,4 +357,7 @@
*/
- (BOOL)shouldBatchFetchForTableView:(ASTableView *)tableView;
@end
@end
@protocol ASTableViewDelegate <ASTableDelegate>;
@end

View File

@@ -8,6 +8,7 @@
#import "ASTableView.h"
#import "ASTableViewInternal.h"
#import "ASTableNode.h"
#import "ASAssert.h"
#import "ASBatchFetching.h"
@@ -20,6 +21,8 @@
#import "ASLayoutController.h"
#import "ASRangeController.h"
#import <CoreFoundation/CoreFoundation.h>
static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
//#define LOG(...) NSLog(__VA_ARGS__)
@@ -79,6 +82,10 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
#pragma mark -
#pragma mark ASTableView
@interface ASTableNode ()
- (instancetype)_initWithStyle:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass;
@end
@interface ASTableView () <ASRangeControllerDataSource, ASRangeControllerDelegate, ASDataControllerSource, _ASTableViewCellDelegate, ASCellNodeLayoutDelegate, ASDelegateProxyInterceptor> {
ASTableViewProxy *_proxyDataSource;
ASTableViewProxy *_proxyDelegate;
@@ -159,33 +166,37 @@ static NSString * const kCellReuseIdentifier = @"_ASTableViewCell";
return [self initWithFrame:frame style:style asyncDataFetching: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];
}
- (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style dataControllerClass:(Class)dataControllerClass asyncDataFetching:(BOOL)asyncDataFetchingEnabled
{
// 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]))
return nil;
// FIXME: asyncDataFetching is currently unreliable for some use cases.
// https://github.com/facebook/AsyncDisplayKit/issues/385
asyncDataFetchingEnabled = NO;
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:asyncDataFetchingEnabled];
if (!dataControllerClass) {
dataControllerClass = [self.class dataControllerClass];
}
[self configureWithDataControllerClass:dataControllerClass asyncDataFetching:NO];
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
if (!(self = [super initWithCoder:aDecoder]))
return nil;
[self configureWithDataControllerClass:[self.class dataControllerClass] asyncDataFetching:NO];
return self;
NSLog(@"Warning: AsyncDisplayKit is not designed to be used with Interface Builder. Table properties set in IB will be lost.");
return [self initWithFrame:CGRectZero style:UITableViewStylePlain];
}
- (void)dealloc

View File

@@ -11,7 +11,7 @@
#import <AsyncDisplayKit/ASDimension.h>
@class ASCollectionView;
@protocol ASCollectionViewDelegate;
@protocol ASCollectionDelegate;
@protocol ASCollectionViewLayoutInspecting <NSObject>
@@ -42,7 +42,7 @@
*
* @discussion A great time to update perform selector caches!
*/
- (void)didChangeCollectionViewDelegate:(id<ASCollectionViewDelegate>)delegate;
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate;
@end

View File

@@ -36,7 +36,7 @@
return self;
}
- (void)didChangeCollectionViewDelegate:(id<ASCollectionViewDelegate>)delegate;
- (void)didChangeCollectionViewDelegate:(id<ASCollectionDelegate>)delegate;
{
if (delegate == nil) {
_delegateImplementsReferenceSizeForHeader = NO;

View File

@@ -49,3 +49,7 @@
@interface ASCollectionViewProxy : ASDelegateProxy
@end
@interface ASPagerNodeProxy : ASDelegateProxy
@end

View File

@@ -60,6 +60,20 @@
@end
@implementation ASPagerNodeProxy
- (BOOL)interceptsSelector:(SEL)selector
{
return (
// handled by ASPagerNodeDataSource node<->cell machinery
selector == @selector(collectionView:nodeForItemAtIndexPath:) ||
selector == @selector(collectionView:numberOfItemsInSection:) ||
selector == @selector(collectionView:constrainedSizeForNodeAtIndexPath:)
);
}
@end
@implementation ASDelegateProxy {
id <NSObject> __weak _target;
id <ASDelegateProxyInterceptor> __weak _interceptor;

View File

@@ -39,33 +39,34 @@
- (ASLayout *)measureWithSizeRange:(ASSizeRange)constrainedSize
{
CGSize size = {
constrainedSize.max.width,
constrainedSize.max.height
};
CGSize maxConstrainedSize = CGSizeMake(constrainedSize.max.width, constrainedSize.max.height);
NSArray *children = self.children;
NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:children.count];
NSMutableArray *sublayouts = [NSMutableArray arrayWithCapacity:self.children.count];
for (id<ASLayoutable> child in self.children) {
CGSize autoMaxSize = {
constrainedSize.max.width - child.layoutPosition.x,
constrainedSize.max.height - child.layoutPosition.y
};
ASSizeRange childConstraint = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, child.sizeRange)
? ASSizeRangeMake({0, 0}, autoMaxSize)
: ASRelativeSizeRangeResolve(child.sizeRange, size);
for (id<ASLayoutable> child in children) {
CGPoint layoutPosition = child.layoutPosition;
CGSize autoMaxSize = CGSizeMake(maxConstrainedSize.width - layoutPosition.x,
maxConstrainedSize.height - layoutPosition.y);
ASRelativeSizeRange childSizeRange = child.sizeRange;
BOOL childIsUnconstrained = ASRelativeSizeRangeEqualToRelativeSizeRange(ASRelativeSizeRangeUnconstrained, childSizeRange);
ASSizeRange childConstraint = childIsUnconstrained ? ASSizeRangeMake({0, 0}, autoMaxSize)
: ASRelativeSizeRangeResolve(childSizeRange, maxConstrainedSize);
ASLayout *sublayout = [child measureWithSizeRange:childConstraint];
sublayout.position = child.layoutPosition;
sublayout.position = layoutPosition;
[sublayouts addObject:sublayout];
}
size.width = constrainedSize.min.width;
for (ASLayout *sublayout in sublayouts) {
size.width = MAX(size.width, sublayout.position.x + sublayout.size.width);
}
CGSize size = CGSizeMake(constrainedSize.min.width, constrainedSize.min.height);
size.height = constrainedSize.min.height;
for (ASLayout *sublayout in sublayouts) {
size.height = MAX(size.height, sublayout.position.y + sublayout.size.height);
CGPoint sublayoutPosition = sublayout.position;
CGSize sublayoutSize = sublayout.size;
size.width = MAX(size.width, sublayoutPosition.x + sublayoutSize.width);
size.height = MAX(size.height, sublayoutPosition.y + sublayoutSize.height);
}
return [ASLayout layoutWithLayoutableObject:self
@@ -75,12 +76,12 @@
- (void)setChild:(id<ASLayoutable>)child forIdentifier:(NSString *)identifier
{
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports setChildren");
ASDisplayNodeAssert(NO, @"ASStaticLayoutSpec only supports setChildren");
}
- (id<ASLayoutable>)childForIdentifier:(NSString *)identifier
{
ASDisplayNodeAssert(NO, @"ASStackLayoutSpec only supports children");
ASDisplayNodeAssert(NO, @"ASStaticLayoutSpec only supports children");
return nil;
}

View File

@@ -7,7 +7,7 @@
*/
#import "_ASCoreAnimationExtras.h"
#import "ASEqualityHelpers.h"
#import "ASAssert.h"
extern void ASDisplayNodeSetupLayerContentsWithResizableImage(CALayer *layer, UIImage *image)
@@ -87,7 +87,8 @@ static const struct _UIContentModeStringLUTEntry UIContentModeDescriptionLUT[] =
{UIViewContentModeBottomRight, @"bottomRight"},
};
NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode) {
NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode)
{
for (int i=0; i< ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
if (UIContentModeDescriptionLUT[i].contentMode == contentMode) {
return UIContentModeDescriptionLUT[i].string;
@@ -96,16 +97,10 @@ NSString *ASDisplayNodeNSStringFromUIContentMode(UIViewContentMode contentMode)
return [NSString stringWithFormat:@"%d", (int)contentMode];
}
UIViewContentMode ASDisplayNodeUIContentModeFromNSString(NSString *string) {
// If you passed one of the constants (this is just an optimization to avoid string comparison)
UIViewContentMode ASDisplayNodeUIContentModeFromNSString(NSString *string)
{
for (int i=0; i < ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
if (UIContentModeDescriptionLUT[i].string == string) {
return UIContentModeDescriptionLUT[i].contentMode;
}
}
// If you passed something isEqualToString: to one of the constants
for (int i=0; i < ARRAY_COUNT(UIContentModeDescriptionLUT); i++) {
if ([UIContentModeDescriptionLUT[i].string isEqualToString:string]) {
if (ASObjectIsEqual(UIContentModeDescriptionLUT[i].string, string)) {
return UIContentModeDescriptionLUT[i].contentMode;
}
}
@@ -126,18 +121,12 @@ NSString *const ASDisplayNodeCAContentsGravityFromUIContentMode(UIViewContentMod
UIViewContentMode ASDisplayNodeUIContentModeFromCAContentsGravity(NSString *const contentsGravity)
{
// If you passed one of the constants (this is just an optimization to avoid string comparison)
for (int i=0; i < ARRAY_COUNT(UIContentModeCAGravityLUT); i++) {
if (UIContentModeCAGravityLUT[i].string == contentsGravity) {
return UIContentModeCAGravityLUT[i].contentMode;
}
}
// If you passed something isEqualToString: to one of the constants
for (int i=0; i < ARRAY_COUNT(UIContentModeCAGravityLUT); i++) {
if ([UIContentModeCAGravityLUT[i].string isEqualToString:contentsGravity]) {
if (ASObjectIsEqual(UIContentModeCAGravityLUT[i].string, contentsGravity)) {
return UIContentModeCAGravityLUT[i].contentMode;
}
}
ASDisplayNodeCAssert(contentsGravity, @"Encountered an unknown contentsGravity \"%@\". Is this a new version of iOS?", contentsGravity);
ASDisplayNodeCAssert(!contentsGravity, @"You passed nil to ASDisplayNodeUIContentModeFromCAContentsGravity. We're falling back to resize, but this is probably a bug.");
// If asserts disabled, fall back to this

View File

@@ -52,7 +52,6 @@
if (_willDeallocBlock) {
_willDeallocBlock(self);
}
[super dealloc];
}
@end
@@ -78,7 +77,6 @@
if (_willDeallocBlock) {
_willDeallocBlock(self);
}
[super dealloc];
}
@end
@@ -130,6 +128,7 @@
@implementation ASTableViewTests
// TODO: Convert this to ARC.
- (void)DISABLED_testTableViewDoesNotRetainItselfAndDelegate
{
ASTestTableView *tableView = [[ASTestTableView alloc] initWithFrame:CGRectZero style:UITableViewStylePlain];
@@ -148,11 +147,11 @@
tableView.asyncDataSource = delegate;
tableView.asyncDelegate = delegate;
[delegate release];
// [delegate release];
XCTAssertTrue(delegateDidDealloc, @"unexpected delegate lifetime:%@", delegate);
XCTAssertNoThrow([tableView release], @"unexpected exception when deallocating table view:%@", tableView);
// XCTAssertNoThrow([tableView release], @"unexpected exception when deallocating table view:%@", tableView);
XCTAssertTrue(tableViewDidDealloc, @"unexpected table view lifetime:%@", tableView);
}
@@ -399,7 +398,10 @@
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;