Merge pull request #1921 from facebook/AHRangeModeUpdatingIssues

[ASRangeController] Fix Major Range Mode Updating Issues
This commit is contained in:
Adlai Holler
2016-07-15 10:22:36 -07:00
committed by GitHub
9 changed files with 70 additions and 33 deletions

View File

@@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
* ASCollectionNode is a node based class that wraps an ASCollectionView. It can be used
* as a subnode of another node, and provide room for many (great) features and improvements later on.
*/
@interface ASCollectionNode : ASDisplayNode
@interface ASCollectionNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol>
- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout;
- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(UICollectionViewLayout *)layout;
@@ -111,8 +111,4 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ASCollectionNode (ASRangeControllerUpdateRangeProtocol) <ASRangeControllerUpdateRangeProtocol>
@end
NS_ASSUME_NONNULL_END

View File

@@ -9,6 +9,7 @@
//
#import "ASContextTransitioning.h"
#import "ASLayoutRangeType.h"
NS_ASSUME_NONNULL_BEGIN
@@ -116,6 +117,15 @@ ASDISPLAYNODE_EXTERN_C_END
*/
- (void)hierarchyDisplayDidFinish;
/**
* Only ASLayoutRangeModeVisibleOnly or ASLayoutRangeModeLowMemory are recommended. Default is ASLayoutRangeModeVisibleOnly,
* because this is the only way to ensure an application will not have blank / flashing views as the user navigates back after
* a memory warning. Apps that wish to use the more effective / aggressive ASLayoutRangeModeLowMemory may need to take steps
* to mitigate this behavior, including: restoring a larger range mode to the next controller before the user navigates there,
* enabling .neverShowPlaceholders on ASCellNodes so that the navigation operation is blocked on redisplay completing, etc.
*/
+ (void)setRangeModeForMemoryWarnings:(ASLayoutRangeMode)rangeMode;
@end
NS_ASSUME_NONNULL_END

View File

@@ -22,7 +22,7 @@
* ASTableNode is a node based class that wraps an ASTableView. It can be used
* as a subnode of another node, and provide room for many (great) features and improvements later on.
*/
@interface ASTableNode : ASDisplayNode
@interface ASTableNode : ASDisplayNode <ASRangeControllerUpdateRangeProtocol>
- (instancetype)init; // UITableViewStylePlain
- (instancetype)initWithStyle:(UITableViewStyle)style;
@@ -34,7 +34,3 @@
@property (weak, nonatomic) id <ASTableDataSource> dataSource;
@end
@interface ASTableNode (ASRangeControllerUpdateRangeProtocol) <ASRangeControllerUpdateRangeProtocol>
@end

View File

@@ -64,7 +64,12 @@ typedef ASTraitCollection * _Nonnull (^ASDisplayTraitsForTraitWindowSizeBlock)(C
@interface ASViewController (ASRangeControllerUpdateRangeProtocol)
/// Automatically adjust range mode based on view events if the containing node confirms to the ASRangeControllerUpdateRangeProtocol
/**
* Automatically adjust range mode based on view events. If you set this to YES, the view controller or its node
* must conform to the ASRangeControllerUpdateRangeProtocol.
*
* Default value is NO.
*/
@property (nonatomic, assign) BOOL automaticallyAdjustRangeModeBasedOnViewEvents;
@end

View File

@@ -27,6 +27,9 @@
BOOL _automaticallyAdjustRangeModeBasedOnViewEvents;
BOOL _parentManagesVisibilityDepth;
NSInteger _visibilityDepth;
BOOL _selfConformsToRangeModeProtocol;
BOOL _nodeConformsToRangeModeProtocol;
BOOL _didCheckRangeModeProtocolConformance;
}
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
@@ -167,12 +170,25 @@ ASVisibilityDepthImplementation;
- (void)updateCurrentRangeModeWithModeIfPossible:(ASLayoutRangeMode)rangeMode
{
if (!_automaticallyAdjustRangeModeBasedOnViewEvents) { return; }
if (![_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]) {
return;
if (!_didCheckRangeModeProtocolConformance) {
_selfConformsToRangeModeProtocol = [self conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_nodeConformsToRangeModeProtocol = [_node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)];
_didCheckRangeModeProtocolConformance = YES;
if (!_selfConformsToRangeModeProtocol && !_nodeConformsToRangeModeProtocol) {
NSLog(@"Warning: automaticallyAdjustRangeModeBasedOnViewEvents set to YES in %@, but range mode updating is not possible because neither view controller nor node %@ conform to ASRangeControllerUpdateRangeProtocol.", self, _node);
}
}
if (_selfConformsToRangeModeProtocol) {
id<ASRangeControllerUpdateRangeProtocol> rangeUpdater = (id<ASRangeControllerUpdateRangeProtocol>)self;
[rangeUpdater updateCurrentRangeWithMode:rangeMode];
}
if (_nodeConformsToRangeModeProtocol) {
id<ASRangeControllerUpdateRangeProtocol> rangeUpdater = (id<ASRangeControllerUpdateRangeProtocol>)_node;
[rangeUpdater updateCurrentRangeWithMode:rangeMode];
}
id<ASRangeControllerUpdateRangeProtocol> updateRangeNode = (id<ASRangeControllerUpdateRangeProtocol>)_node;
[updateRangeNode updateCurrentRangeWithMode:rangeMode];
}
#pragma mark - Layout Helpers

View File

@@ -599,3 +599,12 @@ static ASLayoutRangeMode __rangeModeForMemoryWarnings = ASLayoutRangeModeVisible
}
@end
@implementation ASDisplayNode (RangeModeConfiguring)
+ (void)setRangeModeForMemoryWarnings:(ASLayoutRangeMode)rangeMode
{
[ASRangeController setRangeModeForMemoryWarnings:rangeMode];
}
@end

View File

@@ -18,21 +18,4 @@
*/
- (void)updateCurrentRangeWithMode:(ASLayoutRangeMode)rangeMode;
/**
* Only ASLayoutRangeModeVisibleOnly or ASLayoutRangeModeLowMemory are recommended. Default is ASLayoutRangeModeVisibleOnly,
* because this is the only way to ensure an application will not have blank / flashing views as the user navigates back after
* a memory warning. Apps that wish to use the more effective / aggressive ASLayoutRangeModeLowMemory may need to take steps
* to mitigate this behavior, including: restoring a larger range mode to the next controller before the user navigates there,
* enabling .neverShowPlaceholders on ASCellNodes so that the navigation operation is blocked on redisplay completing, etc.
*/
+ (void)setRangeModeForMemoryWarnings:(ASLayoutRangeMode)rangeMode;
@end

View File

@@ -13,6 +13,7 @@
#import "ASCollectionDataController.h"
#import "ASCollectionViewFlowLayoutInspector.h"
#import "ASCellNode.h"
#import "ASCollectionNode.h"
@interface ASTextCellNodeWithSetSelectedCounter : ASTextCellNode
@@ -241,4 +242,14 @@
XCTAssertTrue(ASRangeTuningParametersEqualToRangeTuningParameters(preloadParams, [collectionView tuningParametersForRangeType:ASLayoutRangeTypeFetchData]));
}
/**
* This may seem silly, but we had issues where the runtime sometimes wouldn't correctly report
* conformances declared on categories.
*/
- (void)testThatCollectionNodeConformsToExpectedProtocols
{
ASCollectionNode *node = [[ASCollectionNode alloc] initWithFrame:CGRectZero collectionViewLayout:[[UICollectionViewFlowLayout alloc] init]];
XCTAssert([node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]);
}
@end

View File

@@ -15,6 +15,7 @@
#import "ASDisplayNode+Subclasses.h"
#import "ASChangeSetDataController.h"
#import "ASCellNode.h"
#import "ASTableNode.h"
#define NumberOfSections 10
#define NumberOfRowsPerSection 20
@@ -518,4 +519,14 @@
}];
}
/**
* This may seem silly, but we had issues where the runtime sometimes wouldn't correctly report
* conformances declared on categories.
*/
- (void)testThatTableNodeConformsToExpectedProtocols
{
ASTableNode *node = [[ASTableNode alloc] initWithStyle:UITableViewStylePlain];
XCTAssert([node conformsToProtocol:@protocol(ASRangeControllerUpdateRangeProtocol)]);
}
@end