iOS4&背景[UIImage setImage:]

发布于 2024-09-07 18:43:13 字数 840 浏览 3 评论 0原文

到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:]),导致我的主线程暂停......即使文档说底层图像缓存在所有线程之间共享。

有什么想法吗?

Up to iOS 3.2, I used this kind of code to load UIImageView image in background, and it worked fine...

Code:

- (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"]

... even if [UIImageView setImage:] was not thread-safe !

But since iOS 4, it doesn't work any more... Images appear on screen two seconds after setImage call. And if I do a [myImageView performSelectorOnMainThread:@selector(setImage:) withObject:newImage waitUntilDone:YES] instead of [myImageView setImage:newImage], images appear immediately but seem to be re-decoded again on-the-fly (ignoring the previous [UIImage imageNamed:] which should have already decoded the image data), causing a pause on my main thread... Even if documentation says The underlying image cache is shared among all threads..

Any thought ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

纸伞微斜 2024-09-14 18:43:13

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

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

:它是新创建的线程安全的 UIImageUIImageView 仍然不是线程安全的。

Don’t do it in the background! It’s not thread-safe. Since an UIImageView is also an NSObject, I think that using -[performSelectorOnMainThread:withObject:waitUntilDone:] on it might work, like:

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

And it’s UIImage which is newly made thread-safe. UIImageView is still not thread-safe.

清风无影 2024-09-14 18:43:13

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

performSelectorInBackground: runs a selector in a background thread. Yet setImage: is a UI function. UI functions should only be run on the main thread. I do not have insight into the particular problem, but this is the first gut feel about this code, and it may be that iOS4 handles the (non-supported) mechanism of running UI functions in background threads somehow differently.

勿忘心安 2024-09-14 18:43:13

如果您使用的是 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];
}

If you're using iOS 4.0, you should really consider reading up on blocks and GCD. Using those technologies, you can simply replace your method with:

- (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];
}
泅人 2024-09-14 18:43:13

我们引用一下:

@property(非原子,只读)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

Let's quote:

@property(nonatomic, readonly) CGImageRef CGImage

Discussion

If the image data has been purged because of memory constraints, invoking this method forces that data to be loaded back into memory. Reloading the image data may incur a performance penalty.

So you might be able to just call image.CGImage. I don't think CGImages are lazy.

If that doesn't work, you can force a render with something like

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

Some people warn about thread-safety. The docs say UIGraphics{Push,Pop,GetCurrent}Context() are main-thread-only but don't mention anything about UIGraphicsBeginImageContext(). If you're worried, use CGBitmapContextCreate and CGContextDrawImage.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文