mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-09-07 05:02:56 +00:00
Summary: This adds support for the concept of visibility depth. Visibility essentially defines the number of user actions it would take a user to have a view controller visible. Knowing a view controllers visibility depth allows view controllers to take action such as clearing out memory that can be restored at a later date. This patch also add two new view controller subclasses which adopt the ASManagesChildVisibilityDepth protocol. Any view controller that has child view controllers can adopt this protocol to indicate to the child what they're visibility is. For example, ASNavigationController will return a visibility depth of it's own visibilityDepth + 1 for a view controller that would be revealed by tapping the back button. Move common implementations to macros Turn off visibility logging Differential Revision: https://phabricator.pinadmin.com/D90395
174 lines
4.6 KiB
Plaintext
174 lines
4.6 KiB
Plaintext
//
|
|
// ASViewController.m
|
|
// AsyncDisplayKit
|
|
//
|
|
// Created by Huy Nguyen on 16/09/15.
|
|
// Copyright (c) 2015 Facebook. All rights reserved.
|
|
//
|
|
|
|
#import "ASViewController.h"
|
|
#import "ASAssert.h"
|
|
#import "ASDimension.h"
|
|
#import "ASDisplayNode+FrameworkPrivate.h"
|
|
#import "ASDisplayNode+Beta.h"
|
|
#import "ASRangeControllerUpdateRangeProtocol+Beta.h"
|
|
|
|
#define AS_LOG_VISIBILITY_CHANGES 0
|
|
|
|
@implementation ASViewController
|
|
{
|
|
BOOL _ensureDisplayed;
|
|
BOOL _automaticallyAdjustRangeModeBasedOnViewEvents;
|
|
BOOL _parentManagesVisibilityDepth;
|
|
NSInteger _visibilityDepth;
|
|
}
|
|
|
|
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
|
{
|
|
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
|
|
return [self initWithNode:[[ASDisplayNode alloc] init]];
|
|
}
|
|
|
|
- (instancetype)initWithCoder:(NSCoder *)aDecoder
|
|
{
|
|
ASDisplayNodeAssert(NO, @"ASViewController requires using -initWithNode:");
|
|
return [self initWithNode:[[ASDisplayNode alloc] init]];
|
|
}
|
|
|
|
- (instancetype)initWithNode:(ASDisplayNode *)node
|
|
{
|
|
if (!(self = [super initWithNibName:nil bundle:nil])) {
|
|
return nil;
|
|
}
|
|
|
|
ASDisplayNodeAssertNotNil(node, @"Node must not be nil");
|
|
ASDisplayNodeAssertTrue(!node.layerBacked);
|
|
_node = node;
|
|
|
|
_automaticallyAdjustRangeModeBasedOnViewEvents = NO;
|
|
|
|
return self;
|
|
}
|
|
|
|
- (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];
|
|
UIView *view = self.view;
|
|
CGRect frame = view.frame;
|
|
UIViewAutoresizing autoresizingMask = view.autoresizingMask;
|
|
|
|
// We have what we need, so now create and assign the view we actually want.
|
|
view = _node.view;
|
|
_node.frame = frame;
|
|
_node.autoresizingMask = autoresizingMask;
|
|
self.view = view;
|
|
}
|
|
|
|
- (void)viewWillLayoutSubviews
|
|
{
|
|
[super viewWillLayoutSubviews];
|
|
[_node measureWithSizeRange:[self nodeConstrainedSize]];
|
|
}
|
|
|
|
- (void)viewDidLayoutSubviews
|
|
{
|
|
if (_ensureDisplayed && self.neverShowPlaceholders) {
|
|
_ensureDisplayed = NO;
|
|
[self.node recursivelyEnsureDisplaySynchronously:YES];
|
|
}
|
|
[super viewDidLayoutSubviews];
|
|
}
|
|
|
|
ASVisibilityDidMoveToParentViewController;
|
|
|
|
- (void)viewWillAppear:(BOOL)animated
|
|
{
|
|
[super viewWillAppear:animated];
|
|
_ensureDisplayed = YES;
|
|
[_node measureWithSizeRange:[self nodeConstrainedSize]];
|
|
[_node recursivelyFetchData];
|
|
|
|
if (_parentManagesVisibilityDepth == NO) {
|
|
_visibilityDepth = 0;
|
|
[self visibilityDepthDidChange];
|
|
}
|
|
}
|
|
|
|
ASVisibilityViewDidDisappearImplementation;
|
|
|
|
ASVisibilityDepthImplementation;
|
|
|
|
- (void)visibilityDepthDidChange
|
|
{
|
|
ASLayoutRangeMode rangeMode = ASLayoutRangeModeForVisibilityDepth(self.visibilityDepth);
|
|
#if AS_LOG_VISIBILITY_CHANGES
|
|
NSString *rangeModeString;
|
|
switch (rangeMode) {
|
|
case ASLayoutRangeModeMinimum:
|
|
rangeModeString = @"Minimum";
|
|
break;
|
|
|
|
case ASLayoutRangeModeFull:
|
|
rangeModeString = @"Full";
|
|
break;
|
|
|
|
case ASLayoutRangeModeVisibleOnly:
|
|
rangeModeString = @"Visible Only";
|
|
break;
|
|
|
|
case ASLayoutRangeModeLowMemory:
|
|
rangeModeString = @"Low Memory";
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
NSLog(@"Updating visibility of:%@ to: %@ (visibility depth: %d)", self, rangeModeString, self.visibilityDepth);
|
|
#endif
|
|
[self updateCurrentRangeModeWithModeIfPossible:rangeMode];
|
|
}
|
|
|
|
#pragma mark - Automatic range mode
|
|
|
|
- (BOOL)automaticallyAdjustRangeModeBasedOnViewEvents
|
|
{
|
|
return _automaticallyAdjustRangeModeBasedOnViewEvents;
|
|
}
|
|
|
|
- (void)setAutomaticallyAdjustRangeModeBasedOnViewEvents:(BOOL)automaticallyAdjustRangeModeBasedOnViewEvents
|
|
{
|
|
_automaticallyAdjustRangeModeBasedOnViewEvents = automaticallyAdjustRangeModeBasedOnViewEvents;
|
|
}
|
|
|
|
- (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode
|
|
{
|
|
if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; }
|
|
if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) {
|
|
return;
|
|
}
|
|
|
|
id<ASRangeControllerUpdateRangeProtocol> updateRangeNode = (id<ASRangeControllerUpdateRangeProtocol>)_node;
|
|
[updateRangeNode updateCurrentRangeWithMode:rangeMode];
|
|
}
|
|
|
|
#pragma mark - Layout Helpers
|
|
|
|
- (ASSizeRange)nodeConstrainedSize
|
|
{
|
|
CGSize viewSize = self.view.bounds.size;
|
|
return ASSizeRangeMake(viewSize, viewSize);
|
|
}
|
|
|
|
- (ASInterfaceState)interfaceState
|
|
{
|
|
return _node.interfaceState;
|
|
}
|
|
|
|
@end
|