Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ios): delete items in a range off screen in list component #3368

Merged
merged 1 commit into from
Jul 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading