Skip to content

Commit

Permalink
feat(ios): delete items in a range off screen in list component
Browse files Browse the repository at this point in the history
  • Loading branch information
ozonelmy authored and zealotchen0 committed Aug 7, 2023
1 parent a51fdc0 commit 285e3ba
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 142 deletions.
111 changes: 101 additions & 10 deletions ios/sdk/component/listview/HippyBaseListView.m
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ @implementation HippyBaseListView {
HippyHeaderRefresh *_headerRefreshView;
HippyFooterRefresh *_footerRefreshView;
NSArray<HippyBaseListViewCell *> *_previousVisibleCells;
NSMutableDictionary<NSIndexPath *, NSNumber *> *_cachedItems;
}

@synthesize node = _node;
Expand All @@ -59,6 +60,10 @@ - (instancetype)initWithBridge:(HippyBridge *)bridge {
_isInitialListReady = NO;
_preNumberOfRows = 0;
_preloadItemNumber = 1;
_cachedItems = [NSMutableDictionary dictionaryWithCapacity:64];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didReceiveMemoryWarning)
name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
[self initTableView];
}

Expand Down Expand Up @@ -169,6 +174,13 @@ - (void)insertHippySubview:(UIView *)subview atIndex:(NSInteger)atIndex {
}
}

- (void)removeHippySubview:(UIView *)subview {
[NSObject cancelPreviousPerformRequestsWithTarget:self
selector:@selector(purgeFurthestIndexPathsFromScreen)
object:nil];
[self purgeFurthestIndexPathsFromScreen];
}

#pragma mark -Scrollable

- (void)setScrollEnabled:(BOOL)value {
Expand Down Expand Up @@ -310,6 +322,7 @@ - (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell
NSAssert([cell isKindOfClass:[HippyBaseListViewCell class]], @"cell must be subclass of HippyBaseListViewCell");
if ([cell isKindOfClass:[HippyBaseListViewCell class]]) {
HippyBaseListViewCell *hippyCell = (HippyBaseListViewCell *)cell;
[_cachedItems setObject:[hippyCell.cellView hippyTag] forKey:indexPath];
hippyCell.node.cell = nil;
}
}
Expand All @@ -324,20 +337,15 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
cell = [[cls alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
cell.tableView = tableView;
}
UIView *cellView = nil;
if (cell.node.cell) {
cellView = [_bridge.uiManager createViewFromNode:indexNode];
} else {
cellView = [_bridge.uiManager updateNode:cell.node withNode:indexNode];
if (nil == cellView) {
cellView = [_bridge.uiManager createViewFromNode:indexNode];
}
}
UIView *cellView = [_bridge.uiManager createViewFromNode:indexNode];
HippyAssert([cellView conformsToProtocol:@protocol(ViewAppearStateProtocol)],
@"subviews of HippyBaseListViewCell must conform to protocol ViewAppearStateProtocol");
cell.cellView = (UIView<ViewAppearStateProtocol> *)cellView;
cell.node = indexNode;
cell.node.cell = cell;
if (cellView) {
[_cachedItems removeObjectForKey:indexPath];
}
return cell;
}

Expand Down Expand Up @@ -381,7 +389,8 @@ - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
[scrollViewListener scrollViewDidScroll:scrollView];
}
}

[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(purgeFurthestIndexPathsFromScreen) object:nil];
[self performSelector:@selector(purgeFurthestIndexPathsFromScreen) withObject:nil afterDelay:.5f];
[_headerRefreshView scrollViewDidScroll];
[_footerRefreshView scrollViewDidScroll];
}
Expand Down Expand Up @@ -538,6 +547,13 @@ - (void)didMoveToSuperview {
_rootView = nil;
}

- (void)didMoveToWindow {
if (!self.window) {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(purgeFurthestIndexPathsFromScreen) object:nil];
[self purgeFurthestIndexPathsFromScreen];
}
}

- (BOOL)isManualScrolling {
return _manualScroll;
}
Expand All @@ -558,7 +574,82 @@ - (BOOL)showScrollIndicator {
return [_tableView showsVerticalScrollIndicator];
}

- (NSUInteger)maxCachedItemCount {
return NSUIntegerMax;
}

- (NSUInteger)differenceFromIndexPath:(NSIndexPath *)indexPath1 againstAnother:(NSIndexPath *)indexPath2 {
NSAssert([NSThread mainThread], @"must be in main thread");
long diffCount = 0;
for (NSUInteger index = MIN([indexPath1 section], [indexPath2 section]); index < MAX([indexPath1 section], [indexPath2 section]); index++) {
diffCount += [_tableView numberOfRowsInSection:index];
}
diffCount = diffCount + [indexPath1 row] - [indexPath2 row];
return labs(diffCount);
}

- (NSInteger)differenceFromIndexPath:(NSIndexPath *)indexPath
againstVisibleIndexPaths:(NSArray<NSIndexPath *> *)visibleIndexPaths {
NSIndexPath *firstIndexPath = [visibleIndexPaths firstObject];
NSIndexPath *lastIndexPath = [visibleIndexPaths lastObject];
NSUInteger diffFirst = [self differenceFromIndexPath:indexPath againstAnother:firstIndexPath];
NSUInteger diffLast = [self differenceFromIndexPath:indexPath againstAnother:lastIndexPath];
return MIN(diffFirst, diffLast);
}

- (NSArray<NSIndexPath *> *)findFurthestIndexPathsFromScreen {
NSUInteger visibleItemsCount = [[self.tableView visibleCells] count];
NSUInteger maxCachedItemCount = [self maxCachedItemCount] == NSUIntegerMax ? visibleItemsCount * 2 : [self maxCachedItemCount];
NSUInteger cachedCount = [_cachedItems count];
NSInteger cachedCountToRemove = cachedCount > maxCachedItemCount ? cachedCount - maxCachedItemCount : 0;
if (0 != cachedCountToRemove) {
NSArray<NSIndexPath *> *visibleIndexPaths = [_tableView indexPathsForVisibleRows];
NSArray<NSIndexPath *> *sortedCachedItemKey = [[_cachedItems allKeys] sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) {
NSIndexPath *ip1 = obj1;
NSIndexPath *ip2 = obj2;
NSUInteger ip1Diff = [self differenceFromIndexPath:ip1 againstVisibleIndexPaths:visibleIndexPaths];
NSUInteger ip2Diff = [self differenceFromIndexPath:ip2 againstVisibleIndexPaths:visibleIndexPaths];
if (ip1Diff > ip2Diff) {
return NSOrderedAscending;
}
else if (ip1Diff < ip2Diff) {
return NSOrderedDescending;
}
else {
return NSOrderedSame;
}
}];
NSArray<NSIndexPath *> *result = [sortedCachedItemKey subarrayWithRange:NSMakeRange(0, cachedCountToRemove)];
return result;
}
return nil;
}

- (void)purgeFurthestIndexPathsFromScreen {
NSArray<NSIndexPath *> *furthestIndexPaths = [self findFurthestIndexPathsFromScreen];
if (furthestIndexPaths) {
//purge view
NSArray<NSNumber *> *objects = [_cachedItems objectsForKeys:furthestIndexPaths notFoundMarker:@(-1)];
[_bridge.uiManager removeNativeViewFromTags:objects];
//purge cache
[_cachedItems removeObjectsForKeys:furthestIndexPaths];
}
}


- (void)didReceiveMemoryWarning {
[self cleanUpCachedItems];
}

- (void)cleanUpCachedItems {
//purge view
NSArray<NSNumber *> *objects = [_cachedItems allValues];
[_bridge.uiManager removeNativeViewFromTags:objects];
[_cachedItems removeAllObjects];
}

- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_headerRefreshView unsetFromScrollView];
[_footerRefreshView unsetFromScrollView];
}
Expand Down
39 changes: 0 additions & 39 deletions ios/sdk/component/waterfalllist/HippyReusableNodeCache.h

This file was deleted.

77 changes: 0 additions & 77 deletions ios/sdk/component/waterfalllist/HippyReusableNodeCache.m

This file was deleted.

Loading

0 comments on commit 285e3ba

Please sign in to comment.