mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Overhaul ASDataController and extensively test ASTableView.
This diff resolves all known consistency issues with ASTableView and ASCollectionView. It includes significantly more aggressive thrash-testing in ASTableViewStressTest, which now passes on a variety of device and simulator configurations. It also updates the unit tests run on every commit to ensure any regression is caught quickly. A few of the salient changes in this diff: - ASTableView now uses Rene's ASCollectionViewLayoutController, and actually uses a UICollectionViewFlowLayout without any UICollectionView. This resolves an issue where ASFlowLayoutController was generating slightly out-of-bounds indicies when programmatically scrolling past the end of the table content. Because the custom implementation is likely faster, I will revisit this later with profiling and possibly returning to the custom impl. - There is now a second copy of the _nodes array maintained by ASDataController. It shares the same node instances, but this does add some overhead to manipulating the arrays. I've filed a task to follow up with optimization, as there are several great opportunities to make it faster. However, I don't believe the overhead is a significant issue, and it does guarantee correctness in even the toughest app usage scenarios. - ASDataController no longer supports calling its delegate /before/ edit operations. No other class was relying on this behavior, and it would be unusual for an app developer to use ASDataController directly. However, it is possible that someone with a custom view that integrates with ASDataController and ASRangeController could be affected by this. - Further cleanup of organization, naming, additional comments, reduced code length wherever possible. Overall, significantly more accessible to a new reader.
This commit is contained in:
@@ -21,7 +21,8 @@ struct ASDirectionalScreenfulBuffer {
|
||||
typedef struct ASDirectionalScreenfulBuffer ASDirectionalScreenfulBuffer;
|
||||
|
||||
ASDirectionalScreenfulBuffer ASDirectionalScreenfulBufferHorizontal(ASScrollDirection scrollDirection,
|
||||
ASRangeTuningParameters rangeTuningParameters) {
|
||||
ASRangeTuningParameters rangeTuningParameters)
|
||||
{
|
||||
ASDirectionalScreenfulBuffer horizontalBuffer = {0, 0};
|
||||
BOOL movingRight = ASScrollDirectionContainsRight(scrollDirection);
|
||||
horizontalBuffer.positiveDirection = movingRight ? rangeTuningParameters.leadingBufferScreenfuls :
|
||||
@@ -32,7 +33,8 @@ ASDirectionalScreenfulBuffer ASDirectionalScreenfulBufferHorizontal(ASScrollDire
|
||||
}
|
||||
|
||||
ASDirectionalScreenfulBuffer ASDirectionalScreenfulBufferVertical(ASScrollDirection scrollDirection,
|
||||
ASRangeTuningParameters rangeTuningParameters) {
|
||||
ASRangeTuningParameters rangeTuningParameters)
|
||||
{
|
||||
ASDirectionalScreenfulBuffer verticalBuffer = {0, 0};
|
||||
BOOL movingDown = ASScrollDirectionContainsDown(scrollDirection);
|
||||
verticalBuffer.positiveDirection = movingDown ? rangeTuningParameters.leadingBufferScreenfuls :
|
||||
@@ -52,44 +54,64 @@ typedef struct ASRangeGeometry ASRangeGeometry;
|
||||
#pragma mark -
|
||||
#pragma mark ASCollectionViewLayoutController
|
||||
|
||||
@interface ASCollectionViewLayoutController () {
|
||||
ASCollectionView * __weak _collectionView;
|
||||
@interface ASCollectionViewLayoutController ()
|
||||
{
|
||||
UIScrollView * __weak _scrollView;
|
||||
UICollectionViewLayout * __strong _collectionViewLayout;
|
||||
std::vector<CGRect> _updateRangeBoundsIndexedByRangeType;
|
||||
ASScrollDirection _scrollableDirections;
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation ASCollectionViewLayoutController
|
||||
|
||||
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView {
|
||||
- (instancetype)initWithCollectionView:(ASCollectionView *)collectionView
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
_collectionView = collectionView;
|
||||
|
||||
_scrollableDirections = [collectionView scrollableDirections];
|
||||
_scrollView = collectionView;
|
||||
_collectionViewLayout = [collectionView collectionViewLayout];
|
||||
_updateRangeBoundsIndexedByRangeType = std::vector<CGRect>(ASLayoutRangeTypeCount);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithScrollView:(UIScrollView *)scrollView collectionViewLayout:(UICollectionViewLayout *)layout
|
||||
{
|
||||
if (!(self = [super init])) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
_scrollableDirections = ASScrollDirectionVerticalDirections;
|
||||
_scrollView = scrollView;
|
||||
_collectionViewLayout = layout;
|
||||
_updateRangeBoundsIndexedByRangeType = std::vector<CGRect>(ASLayoutRangeTypeCount);
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Index Paths in Range
|
||||
|
||||
- (NSSet *)indexPathsForScrolling:(ASScrollDirection)scrollDirection
|
||||
viewportSize:(CGSize)viewportSize
|
||||
rangeType:(ASLayoutRangeType)rangeType {
|
||||
rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
ASRangeGeometry rangeGeometry = [self rangeGeometryWithScrollDirection:scrollDirection
|
||||
collectionView:_collectionView
|
||||
rangeTuningParameters:[self tuningParametersForRangeType:rangeType]];
|
||||
_updateRangeBoundsIndexedByRangeType[rangeType] = rangeGeometry.updateBounds;
|
||||
return [self indexPathsForItemsWithinRangeBounds:rangeGeometry.rangeBounds collectionView:_collectionView];
|
||||
return [self indexPathsForItemsWithinRangeBounds:rangeGeometry.rangeBounds];
|
||||
}
|
||||
|
||||
- (ASRangeGeometry)rangeGeometryWithScrollDirection:(ASScrollDirection)scrollDirection
|
||||
collectionView:(ASCollectionView *)collectionView
|
||||
rangeTuningParameters:(ASRangeTuningParameters)rangeTuningParameters {
|
||||
CGRect rangeBounds = collectionView.bounds;
|
||||
CGRect updateBounds = collectionView.bounds;
|
||||
ASScrollDirection scrollableDirections = [collectionView scrollableDirections];
|
||||
rangeTuningParameters:(ASRangeTuningParameters)rangeTuningParameters
|
||||
{
|
||||
CGRect rangeBounds = _scrollView.bounds;
|
||||
CGRect updateBounds = _scrollView.bounds;
|
||||
|
||||
BOOL canScrollHorizontally = ASScrollDirectionContainsHorizontalDirection(scrollableDirections);
|
||||
BOOL canScrollHorizontally = ASScrollDirectionContainsHorizontalDirection(_scrollableDirections);
|
||||
if (canScrollHorizontally) {
|
||||
ASDirectionalScreenfulBuffer horizontalBuffer = ASDirectionalScreenfulBufferHorizontal(scrollDirection,
|
||||
rangeTuningParameters);
|
||||
@@ -102,7 +124,7 @@ typedef struct ASRangeGeometry ASRangeGeometry;
|
||||
MIN(horizontalBuffer.positiveDirection * 0.5, 0.95));
|
||||
}
|
||||
|
||||
BOOL canScrollVertically = ASScrollDirectionContainsVerticalDirection(scrollableDirections);
|
||||
BOOL canScrollVertically = ASScrollDirectionContainsVerticalDirection(_scrollableDirections);
|
||||
if (canScrollVertically) {
|
||||
ASDirectionalScreenfulBuffer verticalBuffer = ASDirectionalScreenfulBufferVertical(scrollDirection,
|
||||
rangeTuningParameters);
|
||||
@@ -118,9 +140,10 @@ typedef struct ASRangeGeometry ASRangeGeometry;
|
||||
return {rangeBounds, updateBounds};
|
||||
}
|
||||
|
||||
- (NSSet *)indexPathsForItemsWithinRangeBounds:(CGRect)rangeBounds collectionView:(ASCollectionView *)collectionView {
|
||||
- (NSSet *)indexPathsForItemsWithinRangeBounds:(CGRect)rangeBounds
|
||||
{
|
||||
NSMutableSet *indexPathSet = [[NSMutableSet alloc] init];
|
||||
NSArray *layoutAttributes = [collectionView.collectionViewLayout layoutAttributesForElementsInRect:rangeBounds];
|
||||
NSArray *layoutAttributes = [_collectionViewLayout layoutAttributesForElementsInRect:rangeBounds];
|
||||
for (UICollectionViewLayoutAttributes *la in layoutAttributes) {
|
||||
[indexPathSet addObject:la.indexPath];
|
||||
}
|
||||
@@ -132,13 +155,14 @@ typedef struct ASRangeGeometry ASRangeGeometry;
|
||||
|
||||
- (BOOL)shouldUpdateForVisibleIndexPaths:(NSArray *)indexPaths
|
||||
viewportSize:(CGSize)viewportSize
|
||||
rangeType:(ASLayoutRangeType)rangeType {
|
||||
rangeType:(ASLayoutRangeType)rangeType
|
||||
{
|
||||
CGRect updateRangeBounds = _updateRangeBoundsIndexedByRangeType[rangeType];
|
||||
if (CGRectIsEmpty(updateRangeBounds)) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
CGRect currentBounds = _collectionView.bounds;
|
||||
CGRect currentBounds = _scrollView.bounds;
|
||||
if (CGRectIsEmpty(currentBounds)) {
|
||||
currentBounds = CGRectMake(0, 0, viewportSize.width, viewportSize.height);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user