【问题标题】:Feel lag when scroll and sametime load full screen image from asset in background thread滚动并同时从后台线程中的资产加载全屏图像时感觉滞后
【发布时间】:2012-12-18 21:48:40
【问题描述】:

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

[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;”。当我评论它时,一切都很好,没有更多的滞后。 所以,我不明白的是,我已经把它放在了后台线程中......

【问题讨论】:

    标签: iphone ios grand-central-dispatch lag alasset


    【解决方案1】:

    好的,我终于解决了问题:

    而不是直接通过获取图像

    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;
    }
    

    【讨论】:

      【解决方案2】:

      您从 Apple 的 PhotosByLocation 中获取的解决方案实际上是获取 最大 分辨率的图像,而不是 全屏 图像。 IOW,它本质上与调用 fullResolutionImage 而不是 fullScreenImage 相同。这如何解决你的问题,我不确定。我正在努力解决同样的性能问题。如果我使用 fullScreenImage,我的滚动会滞后。但是切换到 fullResolutionImage 可以摆脱滞后。 fullResolutionImage 花费的时间大约是 fullScreenImage 的两倍,但由于它始终在后台,因此花费多少时间并不重要。我怀疑 fullScreenImage 正在返回一个图像,一旦它在主线程中渲染到屏幕上,就需要某种额外的处理 - 因此存在滞后。

      【讨论】:

        【解决方案3】:

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

        鉴于您已经在 BG 线程中加载,因此可能值得将图像大小调整为您正在显示的大小,然后再将其粘贴到屏幕上。

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

        【讨论】:

        • 感谢您的回复。是的,照片的尺寸是全屏尺寸,实际尺寸是一半左右。即使我评论了这一行:“imageView.image = image;”它仍然滞后。这意味着它不是来自调整大小。我知道时间花在了哪里,在这里:“asset.defaultRepresentation.fullScreenImage;”。当我评论它时,一切都很好,没有更多的滞后。我不明白的是,我已经在 bg 线程中做了......
        • 如果您在仪器中使用时间分析器工具进行分析,您将开始了解为什么它在该特定行处变慢。绝对值得一试。
        • 谢谢,我试过了。最后,我使用 Appel 示例中的方法解决了这个问题。我发布了答案。但我不明白为什么会这样......
        【解决方案4】:

        来自苹果文档:

        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

        【讨论】:

        • 感谢您的回复。我试过了,但还是有问题。
        猜你喜欢
        • 1970-01-01
        • 2017-07-10
        • 2019-03-31
        • 2019-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-22
        相关资源
        最近更新 更多