Iphone 当滚动和sametime从后台线程中的资源加载全屏图像时感觉滞后

Iphone 当滚动和sametime从后台线程中的资源加载全屏图像时感觉滞后,iphone,ios,grand-central-dispatch,lag,alasset,Iphone,Ios,Grand Central Dispatch,Lag,Alasset,事情是这样的: 我有一个滚动视图,它对用户照片的全屏图像进行了延迟加载: [self.assetsLibrary assetForURL:[NSURL URLWithString:[[self.assets objectAtIndex:index] objectForKey:@"asset_url"]] resultBlock:^(ALAsset *asset) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUE

事情是这样的: 我有一个滚动视图,它对用户照片的全屏图像进行了延迟加载:

[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:照片的大小是全屏大小,actuel imageView的大小大约是一半。甚至我也评论了这句话:“imageView.image=image”;它仍然是滞后的。这意味着它不是从调整大小。我知道时间花在哪里,这里是:“asset.defaultRepresentation.fullScreenImage;”。当我评论它时,一切都很好,没有更多的滞后。
所以,我不明白的是,我已经把它放在背景线程中了…

你知道照片的实际大小吗?非常昂贵的是滚动正在调整大小以适应屏幕的图像

- (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;
}
鉴于您已经在加载BG线程,在将图像粘贴到屏幕上之前,可能需要将图像大小调整为显示图像的大小


通过在Instruments中使用CoreAnimation工具,通过从Xcode分析应用程序,您可以看到所花费的时间。它甚至会告诉你是哪一行代码导致了速度减慢和动画帧丢失。

来自苹果文档:

DISPATCH\u QUEUE\u PRIORITY\u DEFAULT
调度到队列的项目以默认优先级运行;在调度所有高优先级队列之后,但在调度任何低优先级队列之前,队列计划执行。

DISPATCH\u queue\u priority\u BACKGROUND
调度到队列的项目以后台优先级运行;在调度了所有高优先级队列并且系统在优先级设置为后台状态的线程上运行项目后,将调度队列执行。这样的线程具有最低优先级,任何磁盘I/O都会被限制,以将对系统的影响降至最低。


您正在一个单独的线程中运行它,但这不一定是“后台”线程。根据我的经验,加载某些内容的后台线程将通过执行UI更新(如滚动UIScrollView)而被完全阻止。您是否尝试过使用
DISPATCH\u QUEUE\u PRIORITY\u BACKGROUND

好的,最后我解决了问题:

而不是直接通过

asset.defaultRepresentation.fullScreenImage
我使用苹果示例中的方法(下面的代码)在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;
}

你从苹果的PhotoByLocation中得到的解决方案实际上是抓取最大的分辨率图像,而不是全屏图像。这与调用fullResolutionImage而不是fullScreenImage基本相同。我不确定这是如何解决你的问题的。我正在努力解决同样的性能问题。如果我使用fullScreenImage,我的滚动会出现延迟。但切换到fullResolutionImage可以消除滞后现象。fullResolutionImage所需的时间大约是fullScreenImage的两倍,但由于它始终位于背景中,因此所需的时间并不重要。我怀疑fullScreenImage返回的图像一旦在主线程中呈现到屏幕上,就需要进行某种额外的处理,因此会出现延迟。

谢谢您的回复。是的,照片的大小是全屏大小,actuel大小是大约一半。甚至我也评论了这句话:“imageView.image=image”;它仍然是滞后的。这意味着它不是从调整大小。我知道时间花在哪里,这里是:“asset.defaultRepresentation.fullScreenImage;”。当我评论它时,一切都很好,没有更多的滞后。我不明白的是,我已经在bg线程中这样做了…如果你在instruments中使用时间分析器工具进行分析,你就会开始了解为什么在那条特定的线路上速度慢。绝对值得一试。谢谢,我试过了。最后,我用Appel例子中的方法解决了这个问题。我张贴了答案。但我不知道为什么这样行…谢谢你的回复。我试过了,但还是有问题。