From fdebe946c98d5c3384e85286620f1e62782ecf4f Mon Sep 17 00:00:00 2001 From: Ilya Grechuhin Date: Thu, 3 Mar 2016 10:46:17 +0300 Subject: [PATCH] [ios] Fixed downloader slow scroll perfomance. --- ...MMapDownloaderLargeCountryTableViewCell.mm | 20 +++--- .../MWMMapDownloaderPlaceTableViewCell.mm | 20 +++--- .../MWMMapDownloaderSubplaceTableViewCell.mm | 20 +++--- .../Cells/MWMMapDownloaderTableViewCell.h | 12 +++- .../Cells/MWMMapDownloaderTableViewCell.mm | 70 +++++++++---------- .../DataSources/MWMMapDownloaderDataSource.mm | 1 - .../MWMMapDownloaderDefaultDataSource.mm | 3 +- .../MWMBaseMapDownloaderViewController.h | 2 - .../MWMBaseMapDownloaderViewController.mm | 40 +++++++++-- 9 files changed, 108 insertions(+), 80 deletions(-) diff --git a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm index 3ee0547c04..7466bf0968 100644 --- a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm +++ b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderLargeCountryTableViewCell.mm @@ -1,3 +1,4 @@ +#import "Common.h" #import "MWMMapDownloaderLargeCountryTableViewCell.h" @interface MWMMapDownloaderLargeCountryTableViewCell () @@ -8,11 +9,19 @@ @implementation MWMMapDownloaderLargeCountryTableViewCell ++ (CGFloat)estimatedHeight +{ + return 62.0; +} + - (void)layoutSubviews { [super layoutSubviews]; - self.mapsCount.preferredMaxLayoutWidth = self.mapsCount.width; - [super layoutSubviews]; + if (isIOS7) + { + self.mapsCount.preferredMaxLayoutWidth = self.mapsCount.width; + [super layoutSubviews]; + } } #pragma mark - Config @@ -29,11 +38,4 @@ : [NSString stringWithFormat:@"%@: %@", L(@"downloader_maps"), @(nodeAttrs.m_mwmCounter)]; } -#pragma mark - Properties - -- (CGFloat)estimatedHeight -{ - return 62.0; -} - @end diff --git a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm index 2a5e07e270..d5d341b6d2 100644 --- a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm +++ b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderPlaceTableViewCell.mm @@ -1,3 +1,4 @@ +#import "Common.h" #import "MWMMapDownloaderPlaceTableViewCell.h" @interface MWMMapDownloaderPlaceTableViewCell () @@ -9,11 +10,19 @@ @implementation MWMMapDownloaderPlaceTableViewCell ++ (CGFloat)estimatedHeight +{ + return 62.0; +} + - (void)layoutSubviews { [super layoutSubviews]; - self.area.preferredMaxLayoutWidth = self.area.width; - [super layoutSubviews]; + if (isIOS7) + { + self.area.preferredMaxLayoutWidth = self.area.width; + [super layoutSubviews]; + } } #pragma mark - Config @@ -28,11 +37,4 @@ self.titleBottomOffset.priority = isAreaVisible ? UILayoutPriorityDefaultLow : UILayoutPriorityDefaultHigh; } -#pragma mark - Properties - -- (CGFloat)estimatedHeight -{ - return 62.0; -} - @end diff --git a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm index 0ac8a61c72..06fc06f43e 100644 --- a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm +++ b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderSubplaceTableViewCell.mm @@ -1,3 +1,4 @@ +#import "Common.h" #import "MWMMapDownloaderSubplaceTableViewCell.h" @interface MWMMapDownloaderSubplaceTableViewCell () @@ -8,11 +9,19 @@ @implementation MWMMapDownloaderSubplaceTableViewCell ++ (CGFloat)estimatedHeight +{ + return 82.0; +} + - (void)layoutSubviews { [super layoutSubviews]; - self.subPlace.preferredMaxLayoutWidth = self.subPlace.width; - [super layoutSubviews]; + if (isIOS7) + { + self.subPlace.preferredMaxLayoutWidth = floor(self.subPlace.width); + [super layoutSubviews]; + } } - (void)setSubplaceText:(NSString *)text @@ -20,11 +29,4 @@ self.subPlace.text = text; } -#pragma mark - Properties - -- (CGFloat)estimatedHeight -{ - return 82.0; -} - @end diff --git a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.h b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.h index b0078de041..bf6e7897bb 100644 --- a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.h +++ b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.h @@ -1,14 +1,20 @@ +#import "MWMFrameworkObservers.h" #import "MWMMapDownloaderProtocol.h" #import "MWMTableViewCell.h" #include "storage/storage.hpp" -@interface MWMMapDownloaderTableViewCell : MWMTableViewCell +@protocol MWMMapDownloaderTableViewCellProtocol -@property (nonatomic, readonly) CGFloat estimatedHeight; ++ (CGFloat)estimatedHeight; + +@end + +@interface MWMMapDownloaderTableViewCell : MWMTableViewCell + +@property (nonatomic) BOOL isHeightCell; @property (weak, nonatomic) id delegate; -- (void)registerObserver; - (void)config:(storage::NodeAttrs const &)nodeAttrs; - (void)setCountryId:(storage::TCountryId const &)countryId; diff --git a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.mm b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.mm index b92f16080d..146c818f02 100644 --- a/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.mm +++ b/iphone/Maps/Classes/MapDownloader/Cells/MWMMapDownloaderTableViewCell.mm @@ -1,19 +1,16 @@ #import "Common.h" #import "MWMCircularProgress.h" -#import "MWMFrameworkListener.h" #import "MWMMapDownloaderTableViewCell.h" #include "Framework.h" -@interface MWMMapDownloaderTableViewCell () +@interface MWMMapDownloaderTableViewCell () @property (nonatomic) MWMCircularProgress * progressView; @property (weak, nonatomic) IBOutlet UIView * stateWrapper; @property (weak, nonatomic) IBOutlet UILabel * title; @property (weak, nonatomic) IBOutlet UILabel * downloadSize; -@property (nonatomic) BOOL isObserver; - @end @implementation MWMMapDownloaderTableViewCell @@ -21,39 +18,32 @@ storage::TCountryId m_countryId; } -#pragma mark - Properties ++ (CGFloat)estimatedHeight +{ + return 52.0; +} - (void)awakeFromNib { [super awakeFromNib]; - [self reset]; + m_countryId = kInvalidCountryId; } - (void)prepareForReuse { [super prepareForReuse]; - [self reset]; -} - -- (void)reset -{ - self.progressView = [[MWMCircularProgress alloc] initWithParentView:self.stateWrapper]; - self.progressView.delegate = self; - [self.progressView setImage:[UIImage imageNamed:@"ic_download"] forState:MWMCircularProgressStateNormal]; - [self.progressView setImage:[UIImage imageNamed:@"ic_download"] forState:MWMCircularProgressStateSelected]; - [self.progressView setImage:[UIImage imageNamed:@"ic_close_spinner"] forState:MWMCircularProgressStateProgress]; - [self.progressView setImage:[UIImage imageNamed:@"ic_close_spinner"] forState:MWMCircularProgressStateSpinner]; - [self.progressView setImage:[UIImage imageNamed:@"ic_download_error"] forState:MWMCircularProgressStateFailed]; - [self.progressView setImage:[UIImage imageNamed:@"ic_check"] forState:MWMCircularProgressStateCompleted]; m_countryId = kInvalidCountryId; } - (void)layoutSubviews { [super layoutSubviews]; - self.title.preferredMaxLayoutWidth = self.title.width; - self.downloadSize.preferredMaxLayoutWidth = self.downloadSize.width; - [super layoutSubviews]; + if (isIOS7) + { + self.title.preferredMaxLayoutWidth = floor(self.title.width); + self.downloadSize.preferredMaxLayoutWidth = floor(self.downloadSize.width); + [super layoutSubviews]; + } } #pragma mark - Config @@ -73,8 +63,11 @@ self.progressView.state = MWMCircularProgressStateNormal; break; case NodeStatus::Downloading: - self.progressView.progress = static_cast(nodeAttrs.m_downloadingProgress.first) / 100.0; + { + auto const & progress = nodeAttrs.m_downloadingProgress; + self.progressView.progress = static_cast(progress.first) / progress.second; break; + } case NodeStatus::InQueue: self.progressView.state = MWMCircularProgressStateSpinner; break; @@ -91,16 +84,6 @@ } } -#pragma mark - Framework observer - -- (void)registerObserver -{ - if (self.isObserver) - return; - [MWMFrameworkListener addObserver:self]; - self.isObserver = YES; -} - #pragma mark - MWMFrameworkStorageObserver - (void)processCountryEvent:(TCountryId const &)countryId @@ -148,11 +131,6 @@ #pragma mark - Properties -- (CGFloat)estimatedHeight -{ - return 52.0; -} - - (void)setCountryId:(storage::TCountryId const &)countryId { if (m_countryId == countryId) @@ -163,4 +141,20 @@ [self config:nodeAttrs]; } +- (MWMCircularProgress *)progressView +{ + if (!_progressView && !self.isHeightCell) + { + _progressView = [[MWMCircularProgress alloc] initWithParentView:self.stateWrapper]; + _progressView.delegate = self; + [_progressView setImage:[UIImage imageNamed:@"ic_download"] forState:MWMCircularProgressStateNormal]; + [_progressView setImage:[UIImage imageNamed:@"ic_download"] forState:MWMCircularProgressStateSelected]; + [_progressView setImage:[UIImage imageNamed:@"ic_close_spinner"] forState:MWMCircularProgressStateProgress]; + [_progressView setImage:[UIImage imageNamed:@"ic_close_spinner"] forState:MWMCircularProgressStateSpinner]; + [_progressView setImage:[UIImage imageNamed:@"ic_download_error"] forState:MWMCircularProgressStateFailed]; + [_progressView setImage:[UIImage imageNamed:@"ic_check"] forState:MWMCircularProgressStateCompleted]; + } + return _progressView; +} + @end diff --git a/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDataSource.mm b/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDataSource.mm index b1556eac26..74ca5b3c45 100644 --- a/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDataSource.mm +++ b/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDataSource.mm @@ -52,7 +52,6 @@ using namespace storage; NSString * reuseIdentifier = [self cellIdentifierForIndexPath:indexPath]; MWMMapDownloaderTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; cell.delegate = self.delegate; - [cell registerObserver]; [self fillCell:cell atIndexPath:indexPath]; return cell; } diff --git a/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDefaultDataSource.mm b/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDefaultDataSource.mm index b33ed245d6..33c4832706 100644 --- a/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDefaultDataSource.mm +++ b/iphone/Maps/Classes/MapDownloader/DataSources/MWMMapDownloaderDefaultDataSource.mm @@ -72,7 +72,6 @@ using namespace storage; - (void)reload { // Get old data for comparison. - NSArray * downloadedCoutryIds = [self.downloadedCoutryIds copy]; NSDictionary *> * countryIds = [self.countryIds copy]; BOOL const hadDownloadedCountries = self.haveDownloadedCountries; @@ -83,7 +82,7 @@ using namespace storage; self.needFullReload = (hadDownloadedCountries != self.haveDownloadedCountries || countryIds.count == 0); if (self.needFullReload) return; - if (hadDownloadedCountries || ![downloadedCoutryIds isEqualToArray:self.downloadedCoutryIds]) + if (self.haveDownloadedCountries) m_reloadSections.push_back(self.downloadedCountrySection); [countryIds enumerateKeysAndObjectsUsingBlock:^(NSString * key, NSArray * obj, BOOL * stop) { diff --git a/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.h b/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.h index 6dbd1e36e1..ee2ab16b80 100644 --- a/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.h +++ b/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.h @@ -6,8 +6,6 @@ @property (weak, nonatomic) IBOutlet UILabel * allMapsLabel; -@property (nonatomic) NSMutableDictionary * offscreenCells; - @property (nonatomic) BOOL showAllMapsView; @property (nonatomic) storage::TCountryId parentCountryId; diff --git a/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.mm b/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.mm index c4afb2ddb8..7d39c25627 100644 --- a/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.mm +++ b/iphone/Maps/Classes/MapDownloader/MWMBaseMapDownloaderViewController.mm @@ -45,6 +45,9 @@ NSString * const kCancelActionTitle = L(@"cancel"); @property (nonatomic) MWMMapDownloaderDataSource * dataSource; @property (nonatomic) MWMMapDownloaderDefaultDataSource * defaultDataSource; +@property (nonatomic) NSMutableDictionary * offscreenCells; +@property (nonatomic) NSMutableDictionary * cellHeightCache; + @end using namespace storage; @@ -88,6 +91,11 @@ using namespace storage; self.title = self.dataSource.isParentRoot ? L(@"download_maps") : L(@(self.parentCountryId.c_str())); } +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration +{ + [self.cellHeightCache removeAllObjects]; +} + #pragma mark - MWMFrameworkStorageObserver - (void)processCountryEvent:(TCountryId const &)countryId @@ -127,6 +135,15 @@ using namespace storage; if (find(childrenId.cbegin(), childrenId.cend(), countryId) != childrenId.cend()) process(); } + + for (MWMMapDownloaderTableViewCell * cell in self.tableView.visibleCells) + [cell processCountryEvent:countryId]; +} + +- (void)processCountry:(TCountryId const &)countryId progress:(TLocalAndRemoteSize const &)progress +{ + for (MWMMapDownloaderTableViewCell * cell in self.tableView.visibleCells) + [cell processCountry:countryId progress:progress]; } #pragma mark - Table @@ -139,7 +156,11 @@ using namespace storage; - (void)configTable { self.tableView.separatorColor = [UIColor blackDividers]; - self.offscreenCells = [NSMutableDictionary dictionary]; + if (isIOS7) + { + self.offscreenCells = [@{} mutableCopy]; + self.cellHeightCache = [@{} mutableCopy]; + } [self registerCellWithIdentifier:kPlaceCellIdentifier]; [self registerCellWithIdentifier:kCountryCellIdentifier]; [self registerCellWithIdentifier:kLargeCountryCellIdentifier]; @@ -349,23 +370,27 @@ using namespace storage; - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if (!isIOS7) + return UITableViewAutomaticDimension; + NSNumber * cacheHeight = self.cellHeightCache[indexPath]; + if (cacheHeight) + return cacheHeight.floatValue; NSString * reuseIdentifier = [self.dataSource cellIdentifierForIndexPath:indexPath]; MWMMapDownloaderTableViewCell * cell = [self offscreenCellForIdentifier:reuseIdentifier]; [self.dataSource fillCell:cell atIndexPath:indexPath]; - [cell setNeedsUpdateConstraints]; - [cell updateConstraintsIfNeeded]; cell.bounds = {{}, {CGRectGetWidth(tableView.bounds), CGRectGetHeight(cell.bounds)}}; [cell setNeedsLayout]; [cell layoutIfNeeded]; CGSize const size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; - return ceil(size.height + 0.5); + CGFloat const height = ceil(size.height + 0.5); + self.cellHeightCache[indexPath] = @(height); + return height; } - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath { - NSString * reuseIdentifier = [self.dataSource cellIdentifierForIndexPath:indexPath]; - MWMMapDownloaderTableViewCell * cell = [self offscreenCellForIdentifier:reuseIdentifier]; - return cell.estimatedHeight; + Class cellClass = NSClassFromString([self.dataSource cellIdentifierForIndexPath:indexPath]); + return [cellClass estimatedHeight]; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section @@ -472,6 +497,7 @@ using namespace storage; - (void)reloadData { + [self.cellHeightCache removeAllObjects]; UITableView * tv = self.tableView; // If these methods are not called, tableView will not call tableView:cellForRowAtIndexPath: [tv setNeedsLayout];