Почувствуйте отставание при прокрутке и одновременно загрузите полноэкранное изображение из ресурса в фоновом потоке
Вот в чем дело: у меня есть вид прокрутки, он сделал ленивую загрузку полноэкранного изображения фотографии пользователя:
[self.assetsLibrary assetForURL:[NSURL URLWithString:[[self.assets objectAtIndex:index] objectForKey:@"asset_url"]]
resultBlock:^(ALAsset *asset) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGImageRef cgImage = asset.defaultRepresentation.fullScreenImage;
UIImage *image = [UIImage imageWithCGImage:cgImage];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = image;
});
});
}
failureBlock:^(NSError *error) {
NSLog(@"error");
}];
Я знаю, что загружать полноэкранное изображение дорого, поэтому я помещаю его в фоновый поток, но при прокрутке оно все еще запаздывает. И все равно лаг даже меняю это так:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGImageRef cgImage = asset.defaultRepresentation.fullScreenImage;
UIImage *image = [UIImage imageWithCGImage:cgImage];
imageView.image = image;
dispatch_async(dispatch_get_main_queue(), ^{
});
});
Очевидно, что ничего не делать в основной очереди, но она все еще запаздывает, пока я не прокомментирую строку:
// CGImageRef cgImage = asset.defaultRepresentation.fullScreenImage;
Так что я так растерялся, что-то не так, когда я использовал GCD? Кто-нибудь может помочь мне объяснить это? Любая вещь будет полезна.
Спасибо вам, ребята.
ОБНОВИТЬ
Для @Fogmeister: размер фотографии соответствует размеру полного экрана, размер изображения в актуальном состоянии составляет около половины. Даже я комментирую строку: "imageView.image = image;" это все еще отставание. Что означает, что это не от изменения размера. Я знаю, где берется время, здесь: "asset.defaultRepresentation.fullScreenImage;". Когда я это комментирую, все нормально, лагов больше нет. Итак, что я не понимаю, я уже положил его в фоновом потоке...
4 ответа
Хорошо, наконец я решил проблему:
Вместо того, чтобы получать изображение напрямую
asset.defaultRepresentation.fullScreenImage
Я использую метод из Apple, например, PhotosByLocation (код ниже), чтобы получить изображение в BG-потоке. Это прекрасно работает, не больше лагов при прокрутке. Но я все еще в замешательстве, я не знаю точно, почему. Поэтому я ценю, если кто-то может мне это объяснить.
- (UIImage *)fullSizeImageForAssetRepresentation:(ALAssetRepresentation *)assetRepresentation {
UIImage *result = nil;
NSData *data = nil;
uint8_t *buffer = (uint8_t *)malloc(sizeof(uint8_t)*[assetRepresentation size]);
if (buffer != NULL) {
NSError *error = nil;
NSUInteger bytesRead = [assetRepresentation getBytes:buffer fromOffset:0 length:[assetRepresentation size] error:&error];
data = [NSData dataWithBytes:buffer length:bytesRead];
free(buffer);
}
if ([data length]) {
CGImageSourceRef sourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
NSMutableDictionary *options = [NSMutableDictionary dictionary];
[options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceShouldAllowFloat];
[options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceCreateThumbnailFromImageAlways];
[options setObject:(id)[NSNumber numberWithFloat:640.0f] forKey:(id)kCGImageSourceThumbnailMaxPixelSize];
//[options setObject:(id)kCFBooleanTrue forKey:(id)kCGImageSourceCreateThumbnailWithTransform];
CGImageRef imageRef = CGImageSourceCreateThumbnailAtIndex(sourceRef, 0, (__bridge CFDictionaryRef)options);
if (imageRef) {
result = [UIImage imageWithCGImage:imageRef scale:[assetRepresentation scale] orientation:(UIImageOrientation)[assetRepresentation orientation]];
CGImageRelease(imageRef);
}
if (sourceRef) CFRelease(sourceRef);
}
return result;
}
Ваше решение взято из Apple PhotosByLocation на самом деле захватывает изображение с самым большим разрешением, а не полноэкранное изображение. IOW, по сути это то же самое, что вызов fullResolutionImage вместо fullScreenImage. Как это решит вашу проблему, я не уверен. Я борюсь с той же проблемой производительности. Если я использую fullScreenImage, у меня возникают задержки при прокрутке. Но переключение на fullResolutionImage избавляет от лагов. fullResolutionImage занимает примерно вдвое больше времени, чем fullScreenImage, но, поскольку это всегда происходит в фоновом режиме, не должно иметь значения, сколько времени это займет. Я подозреваю, что fullScreenImage возвращает изображение, которое требует какой-то дополнительной обработки, как только оно отображается на экране в главном потоке - отсюда и задержка.
Из яблочной документации:
DISPATCH_QUEUE_PRIORITY_DEFAULT
Items dispatched to the queue run at the default priority; the queue is scheduled for execution after all high priority queues have been scheduled, but before any low priority queues have been scheduled.
DISPATCH_QUEUE_PRIORITY_BACKGROUND
Items dispatched to the queue run at background priority; the queue is scheduled for execution after all high priority queues have been scheduled and the system runs items on a thread whose priority is set for background status. Such a thread has the lowest priority and any disk I/O is throttled to minimize the impact on the system.
Вы запускаете его в отдельном потоке, но это не обязательно поток "в фоновом режиме". Фоновый поток, загружающий что-то в моем опыте, будет полностью заблокирован обновлением пользовательского интерфейса, например прокруткой UIScrollView. Вы пытались использовать DISPATCH_QUEUE_PRIORITY_BACKGROUND
?
Вы знаете реальный размер фотографии? Что очень дорого, так это прокрутка изображений, размер которых изменяется по размеру экрана.
Поскольку вы уже загружаете BG-поток, возможно, стоит изменить размер изображения до размера, в котором вы его отображаете, прежде чем вставлять его на экран.
Вы можете увидеть, где идет время, используя инструмент CoreAnimation в Инструментах, профилируя приложение из XCode. Он даже скажет вам, какая строка кода вызывает замедление и пропущенные кадры анимации.