这是事情: 我有一个滚动视图,它为用户照片的全屏图像做了延迟加载:
[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时出了什么问题? 有人可以帮我解释一下吗?任何事情都会有所帮助。
谢谢你们,伙计们。
更新
To @Fogmeister:照片的大小是全屏尺寸,图像尺寸约为一半。甚至我评论这一行:“imageView.image = image;”它仍然滞后。这意味着它不是来自调整大小。我知道时间在哪里,这里:“asset.defaultRepresentation.fullScreenImage;”。当我评论它,一切都很好,没有更多的滞后。 所以,我不明白的是,我已经把它放在后台线程中......
答案 0 :(得分:5)
好的,最后我解决了问题:
而不是直接通过
获取图像asset.defaultRepresentation.fullScreenImage
我使用Apple的Exemple 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;
}
答案 1 :(得分:1)
您从Apple的PhotosByLocation获取的解决方案实际上是抓取最大分辨率图像,而不是全屏图像。 IOW,它与调用fullResolutionImage而不是fullScreenImage基本相同。如何解决你的问题,我不确定。我正在努力解决相同的性能问题。如果我使用fullScreenImage,我的滚动会滞后。但是切换到fullResolutionImage摆脱了滞后。 fullResolutionImage大约需要fullScreenImage的两倍,但由于这总是在后台,所以它花费的时间并不重要。我怀疑fullScreenImage返回的图像一旦被渲染到主线程中的屏幕就需要某种额外的处理 - 因此滞后。
答案 2 :(得分:0)
你知道照片的实际尺寸吗?非常昂贵的是滚动正在调整大小以适应屏幕的图像。
看到你已经加载了一个BG线程,在将图像粘贴到屏幕上之前,可能需要将图像大小调整到你显示的大小。
您可以通过使用Xcode中的应用程序分析应用程序中的CoreAnimation工具来查看时间。它甚至会告诉你哪一行代码导致减速和错过动画帧。
答案 3 :(得分:0)
来自苹果文档:
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.
你是在一个单独的线程中运行它,但这不一定是“在后台”的线程。通过执行UI更新(例如滚动UIScrollView)可以完全阻止在我的经验中加载某些内容的后台线程。您是否尝试过使用DISPATCH_QUEUE_PRIORITY_BACKGROUND
?