From 62f378a9fd116c1a59fd285245b4553d4d8d180b Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sun, 27 Nov 2016 15:42:07 -0800 Subject: [PATCH 1/2] This patch enables memory warning support on ASRangeController by default It also fixes a couple subtle bugs: 1. If a range controller update was in flight and you were manually setting the range mode, you could actually clear out the range mode by calling updateCurrentRangeWithMode: This is fixed by setting _didUpdateCurrentRange = YES if _needsRangeUpdate is YES. 2. Calling setNeedsUpdate after calling updateCurrentRangeWithMode: can cause the current range mode to get cleared out. This is because updateCurrentRangeWithMode: will not set _didUpdateCurrentRange if _currentRangeMode == rangeMode. --- AsyncDisplayKit/Details/ASRangeController.mm | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index 90e814dcbe..72669aeac9 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -24,6 +24,10 @@ #define AS_RANGECONTROLLER_LOG_UPDATE_FREQ 0 +#ifndef ASRangeControllerAutomaticLowMemoryHandling +#define ASRangeControllerAutomaticLowMemoryHandling 1 +#endif + @interface ASRangeController () { BOOL _rangeIsValid; @@ -145,6 +149,10 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; _didUpdateCurrentRange = YES; [self setNeedsUpdate]; + } else if (_needsRangeUpdate) { + // If _needsRangeUpdate is YES, but we don't set didUpdateCurrentRange, it + // will be overridden. + _didUpdateCurrentRange = YES; } } @@ -532,7 +540,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; [center addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; } -static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeVisibleOnly; +static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeLowMemory; + (void)setRangeModeForMemoryWarnings:(ASLayoutRangeMode)rangeMode { ASDisplayNodeAssert(rangeMode == ASLayoutRangeModeVisibleOnly || rangeMode == ASLayoutRangeModeLowMemory, @"It is highly inadvisable to engage a larger range mode when a memory warning occurs, as this will almost certainly cause app eviction"); @@ -544,8 +552,8 @@ static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeVisible NSArray *allRangeControllers = [[self allRangeControllersWeakSet] allObjects]; for (ASRangeController *rangeController in allRangeControllers) { BOOL isDisplay = ASInterfaceStateIncludesDisplay([rangeController interfaceState]); - [rangeController updateCurrentRangeWithMode:isDisplay ? ASLayoutRangeModeMinimum : __rangeModeForMemoryWarnings]; - [rangeController setNeedsUpdate]; + [rangeController updateCurrentRangeWithMode:isDisplay ? ASLayoutRangeModeVisibleOnly : __rangeModeForMemoryWarnings]; + // There's no need to call needs update as updateCurrentRangeWithMode sets this if necessary. [rangeController updateIfNeeded]; } @@ -568,7 +576,7 @@ static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeVisible __ApplicationState = UIApplicationStateBackground; for (ASRangeController *rangeController in allRangeControllers) { // Trigger a range update immediately, as we may not be allowed by the system to run the update block scheduled by changing range mode. - [rangeController setNeedsUpdate]; + // There's no need to call needs update as updateCurrentRangeWithMode sets this if necessary. [rangeController updateIfNeeded]; } From 04dc582a7a0d8c67be36190b4fff2761f1044b6e Mon Sep 17 00:00:00 2001 From: Garrett Moon Date: Sun, 27 Nov 2016 16:05:31 -0800 Subject: [PATCH 2/2] Rename didUpdateCurrentRangeMode to preserveCurrentRangeMode --- AsyncDisplayKit/Details/ASRangeController.mm | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/AsyncDisplayKit/Details/ASRangeController.mm b/AsyncDisplayKit/Details/ASRangeController.mm index 72669aeac9..0b608d9a19 100644 --- a/AsyncDisplayKit/Details/ASRangeController.mm +++ b/AsyncDisplayKit/Details/ASRangeController.mm @@ -36,7 +36,7 @@ BOOL _layoutControllerImplementsSetViewportSize; NSSet *_allPreviousIndexPaths; ASLayoutRangeMode _currentRangeMode; - BOOL _didUpdateCurrentRange; + BOOL _preserveCurrentRangeMode; BOOL _didRegisterForNodeDisplayNotifications; CFTimeInterval _pendingDisplayNodesTimestamp; @@ -62,7 +62,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; _rangeIsValid = YES; _currentRangeMode = ASLayoutRangeModeInvalid; - _didUpdateCurrentRange = NO; + _preserveCurrentRangeMode = NO; [[[self class] allRangeControllersWeakSet] addObject:self]; @@ -144,15 +144,11 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; - (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode { + _preserveCurrentRangeMode = YES; if (_currentRangeMode != rangeMode) { _currentRangeMode = rangeMode; - _didUpdateCurrentRange = YES; [self setNeedsUpdate]; - } else if (_needsRangeUpdate) { - // If _needsRangeUpdate is YES, but we don't set didUpdateCurrentRange, it - // will be overridden. - _didUpdateCurrentRange = YES; } } @@ -224,7 +220,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; ASLayoutRangeMode rangeMode = _currentRangeMode; // If the range mode is explicitly set via updateCurrentRangeWithMode: it will last in that mode until the // range controller becomes visible again or explicitly changes the range mode again - if ((!_didUpdateCurrentRange && ASInterfaceStateIncludesVisible(selfInterfaceState)) || [[self class] isFirstRangeUpdateForRangeMode:rangeMode]) { + if ((!_preserveCurrentRangeMode && ASInterfaceStateIncludesVisible(selfInterfaceState)) || [[self class] isFirstRangeUpdateForRangeMode:rangeMode]) { rangeMode = [ASRangeController rangeModeForInterfaceState:selfInterfaceState currentRangeMode:_currentRangeMode]; } @@ -267,7 +263,7 @@ static UIApplicationState __ApplicationState = UIApplicationStateActive; _allPreviousIndexPaths = allCurrentIndexPaths; _currentRangeMode = rangeMode; - _didUpdateCurrentRange = NO; + _preserveCurrentRangeMode = NO; if (!_rangeIsValid) { [allIndexPaths addObjectsFromArray:ASIndexPathsForTwoDimensionalArray(allNodes)]; @@ -592,7 +588,7 @@ static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeLowMemo for (ASRangeController *rangeController in allRangeControllers) { BOOL isVisible = ASInterfaceStateIncludesVisible([rangeController interfaceState]); [rangeController updateCurrentRangeWithMode:isVisible ? ASLayoutRangeModeMinimum : ASLayoutRangeModeVisibleOnly]; - [rangeController setNeedsUpdate]; + // There's no need to call needs update as updateCurrentRangeWithMode sets this if necessary. [rangeController updateIfNeeded]; }