У меня есть UITableView
со многими строками (+1000). Я получаю строки из этих UITableView
один раз с помощью NSFetchedResultsController
и fetchBatchSize
в viewDidLoad
, как показано ниже:Lazy loading heightForRowAtIndexPath в UITableView со многими строками
@interface MessagesViewController()
@property (nonatomic, strong) NSFetchedResultsController *messagesFRC;
@end
@implementation MessagesViewController
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.messagesFRC == nil) {
// Read in Model.xcdatamodeld
NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
NSPersistentStoreCoordinator *psc =
[[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
// Where does the SQLite file go?
NSArray *documentDirectories =
NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask,
YES);
// Get one and only document directory from that list
NSString *documentDirectory = [documentDirectories firstObject];
NSString *path = [documentDirectory stringByAppendingPathComponent:@"model.sqlite"];
NSURL *storeURL = [NSURL fileURLWithPath:path];
NSError *error = nil;
if (![psc addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeURL
options:nil
error:&error]) {
@throw [NSException exceptionWithName:@"OpenFailure"
reason:[error localizedDescription]
userInfo:nil];
}
// Create the managed object context
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
context.persistentStoreCoordinator = psc;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSString *entityName = @"Message";
NSString *sortAttribute = @"timestamp";
NSEntityDescription *e = [NSEntityDescription entityForName:entityName
inManagedObjectContext:context];
request.entity = e;
NSSortDescriptor *sd = [NSSortDescriptor
sortDescriptorWithKey:sortAttribute
ascending:NO];
request.sortDescriptors = @[sd];
// request.fetchLimit = 30;
request.fetchBatchSize = 60;
self.messagesFRC = [[NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath:nil cacheName:nil];
NSError *error3 = nil;
if (![self.messagesFRC performFetch:&error3]) {
NSLog(@"Failed to initialize FetchedResultsController: %@\n%@", [error localizedDescription], [error userInfo]);
abort();
}
self.messagesFRC.delegate = self;
}
}
@end
Также я установить высоту каждой ячейки с heightForRowAtIndexPath
в этом контроллере:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([tableView isEqual:self.tableView]) {
NSManagedObject *row = [self.messagesFRC objectAtIndexPath:indexPath];
NSString *messageText = [[NSString alloc] initWithData:[row valueForKey:@"text"] encoding:NSUTF8StringEncoding];
messageText = [[GeneralHelper convertHtmlToString:messageText] stringByReplacingOccurrencesOfString:@"\n" withString:@" "];
// messageText = @"yes\r\nnew";
NSMutableParagraphStyle *paragraphStyle = [NSMutableParagraphStyle new];
paragraphStyle.lineBreakMode = NSLineBreakByWordWrapping;
paragraphStyle.alignment = NSTextAlignmentRight;
// paragraphStyle.
NSDictionary *attributes = @{NSFontAttributeName: self.messageFont,
NSParagraphStyleAttributeName: paragraphStyle}; // TODO: Font
CGFloat width = CGRectGetWidth(tableView.frame)-kMessageTableViewCellAvatarHeight;
width -= 25.0;
CGRect titleBounds = [[row valueForKey:@"title"] boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:NULL];
CGRect bodyBounds = [messageText boundingRectWithSize:CGSizeMake(width, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:attributes context:NULL];
if (messageText.length == 0) {
return 0.0;
}
CGFloat height = CGRectGetHeight(titleBounds);
height += CGRectGetHeight(bodyBounds);
height += 40.0;
if (height < kMessageTableViewCellMinimumHeight) {
height = kMessageTableViewCellMinimumHeight;
}
return height;
}
else {
return kMessageTableViewCellMinimumHeight;
}
}
Проблема в том, что загружая UITableView длительное время (более 15 секунд) из-за установки высоты всех ячеек в начале рабочего процесса. Поэтому мне нужна ленивая загрузка по heightForRowAtIndexPath
для каждых 30 ячеек, а затем, прокручивая вверх и вниз, получите следующую 30 ячеек.
Кроме того, я проверить UITableViewAutomaticDimension
для IOS 7+, но он имел очень высокую загрузку процессора:
-(CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
return UITableViewAutomaticDimension;
}
Как решить эту проблему?
Вы можете попробовать использовать '- tableView: expectedHeightForRowAtIndexPath:' – Avi
Прочтите его еще раз, в последней части вопроса я упомянул об этом. –
Кроме того, представление таблицы загружает только видимые ячейки, поэтому для них будет называться 'heightForRowAtIndexPath'. Если вы регистрируете или устанавливаете точку останова, вы можете это увидеть сами. – Avi