iOS4&背景[UIImage setImage:]

时间:2010-06-28 00:16:08

标签: multithreading ios4 uiimage

在iOS 3.2之前,我使用这种代码在后台加载UIImageView图片,而且效果很好......

代码:

- (void)decodeImageName:(NSString *)name
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    UIImage *newImage = [UIImage imageNamed:name];
    [myImageView setImage:newImage];
    [pool release];
}
...
[self performSelectorInBackground:@selector(decodeImageName:) withObject:@"ID"]

...即使[UIImageView setImage:]不是线程安全的!

但是从iOS 4开始,它不再起作用了... setImage调用后两秒钟,图像出现在屏幕上。如果我执行[myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:YES]而不是[myImageView setImage:newImage],图像会立即显示,但似乎会在运行中再次重新解码(忽略之前应该已解码图像的[UIImage imageNamed:]数据),导致我的主线程暂停...即使文档说基础图像缓存在所有线程之间共享。

有什么想法吗?

4 个答案:

答案 0 :(得分:4)

不要在后台执行此操作!它不是线程安全的。由于UIImageView也是NSObject,我认为在其上使用-[performSelectorOnMainThread:withObject:waitUntilDone:]可能会有效,例如:

[myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:NO];

它是UIImage,它是新制作的线程安全的。 UIImageView仍然不是线程安全的。

答案 1 :(得分:3)

performSelectorInBackground:在后​​台线程中运行选择器。然而,setImage:是一个UI功能。 UI函数应该只在主线程上运行。我没有深入了解特定问题,但这是对此代码的第一个直觉,可能是iOS4处理在后台线程中以某种方式运行UI函数的(不支持)机制。

答案 2 :(得分:1)

如果你使用的是iOS 4.0,你应该真的考虑读取块和GCD。使用这些技术,您只需用以下方法替换您的方法:

- (void)decodeImageName:(NSString *)name
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    UIImage *newImage = [UIImage imageNamed:name];

    dispatch_async(dispatch_get_main_queue(), ^{
        [myImageView setImage:newImage];
    }

    [pool release];
}

答案 3 :(得分:1)

让我们引用:

  

@property(nonatomic, readonly) CGImageRef CGImage

     

<强>讨论

     

如果由于内存限制而清除了图像数据,则调用此方法会强制将该数据加载回内存。重新加载图像数据可能会导致性能下降。

所以你可以打电话给image.CGImage。我不认为CGImages是懒惰的。

如果这不起作用,您可以强制使用类似

的渲染
// Possibly only safe in the main thread...
UIGraphicsBeginImageContext((CGSize){1,1});
[image drawInRect:(CGRect){1,1}];
UIGraphicsEndImageContext();

有些人警告线程安全。文档说UIGraphics{Push,Pop,GetCurrent}Context()仅是主线程,但没有提到有关UIGraphicsBeginImageContext()的任何内容。如果您担心,请使用CGBitmapContextCreateCGContextDrawImage