[ASViewController] Support optional node (#3021)

* ASViewController can be used without a node
- If a node isn't provided by developers via -initWithNode:, a default one will be created and used internally.
- This allows developers to use ASViewController like a normal UIViewController and as a base class for all view controllers among which some use a node hierarchy and some don't.

* Update ASDKgram to use a shared base ASViewController

* Minor fixes in ASViewController:
- If its node isn't provided by users, don't replace the view controller's view with the default node's view because it might be loaded from a nib.
- Init a vanilla ASDisplayNode if a node isn't provided.

* Some smaller cleanup

* Remove dummy node for ASViewController if it’s used without a node
This commit is contained in:
Michael Schneider
2017-02-14 13:18:59 -08:00
committed by GitHub
parent cd448a105e
commit aecd36a4df
12 changed files with 265 additions and 206 deletions

View File

@@ -33,14 +33,24 @@
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
return [self initWithNode:[[ASDisplayNode alloc] init]];
if (!(self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
return nil;
}
[self _initializeInstance];
return self;
}
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
return [self initWithNode:[[ASDisplayNode alloc] init]];
if (!(self = [super initWithCoder:aDecoder])) {
return nil;
}
[self _initializeInstance];
return self;
}
- (instancetype)initWithNode:(ASDisplayNode *)node
@@ -49,10 +59,18 @@
return nil;
}
ASDisplayNodeAssertNotNil(node, @"Node must not be nil");
ASDisplayNodeAssertTrue(!node.layerBacked);
_node = node;
[self _initializeInstance];
return self;
}
- (void)_initializeInstance
{
if (_node == nil) {
return;
}
_selfConformsToRangeModeProtocol = [self conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_nodeConformsToRangeModeProtocol = [_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_automaticallyAdjustRangeModeBasedOnViewEvents = _selfConformsToRangeModeProtocol || _nodeConformsToRangeModeProtocol;
@@ -62,7 +80,7 @@
// Node already loaded the view
[self view];
} else {
// If the node didn't load yet add ourselves as on did load observer to laod the view in case the node gets loaded
// If the node didn't load yet add ourselves as on did load observer to load the view in case the node gets loaded
// before the view controller
__weak __typeof__(self) weakSelf = self;
[_node onDidLoad:^(__kindof ASDisplayNode * _Nonnull node) {
@@ -71,8 +89,6 @@
}
}];
}
return self;
}
- (void)dealloc
@@ -82,13 +98,18 @@
- (void)loadView
{
ASDisplayNodeAssertTrue(!_node.layerBacked);
// Apple applies a frame and autoresizing masks we need. Allocating a view is not
// nearly as expensive as adding and removing it from a hierarchy, and fortunately
// we can avoid that here. Enabling layerBacking on a single node in the hierarchy
// will have a greater performance benefit than the impact of this transient view.
[super loadView];
if (_node == nil) {
return;
}
ASDisplayNodeAssertTrue(!_node.layerBacked);
UIView *view = self.view;
CGRect frame = view.frame;
UIViewAutoresizing autoresizingMask = view.autoresizingMask;
@@ -135,7 +156,7 @@
{
if (_ensureDisplayed && self.neverShowPlaceholders) {
_ensureDisplayed = NO;
[self.node recursivelyEnsureDisplaySynchronously:YES];
[_node recursivelyEnsureDisplaySynchronously:YES];
}
[super viewDidLayoutSubviews];
}
@@ -212,7 +233,9 @@ ASVisibilityDepthImplementation;
- (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode
{
if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; }
if (!_automaticallyAdjustRangeModeBasedOnViewEvents) {
return;
}
if (_selfConformsToRangeModeProtocol) {
id<ASRangeControllerUpdateRangeProtocol> rangeUpdater = (id<ASRangeControllerUpdateRangeProtocol>)self;
@@ -268,7 +291,7 @@ ASVisibilityDepthImplementation;
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// Once we've propagated all the traits, layout this node.
// Remeasure the node with the latest constrained size old constrained size may be incorrect.
[self.node layoutThatFits:[self nodeConstrainedSize]];
[_node layoutThatFits:[self nodeConstrainedSize]];
#pragma clang diagnostic pop
}
}
@@ -286,7 +309,7 @@ ASVisibilityDepthImplementation;
{
[super didRotateFromInterfaceOrientation:fromInterfaceOrientation];
ASPrimitiveTraitCollection traitCollection = self.node.primitiveTraitCollection;
ASPrimitiveTraitCollection traitCollection = _node.primitiveTraitCollection;
traitCollection.containerSize = self.view.bounds.size;
[self propagateNewTraitCollection:traitCollection];
}