UIImage imageNamed 未正确自动释放

发布于 2024-09-03 00:20:08 字数 1601 浏览 1 评论 0原文

由于某种原因,以下代码中的保留/释放行为让我完全困惑。

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

应该会被破坏,但却没有。为什么?我认为 imageNamed 本身会自动释放,这意味着这里的释放是多余的,并且应该在自动释放发生时中断。

以下是 .h 和 .m 文件中与 selectedImage 相关的片段:

@property (nonatomic, readonly) UIImage *selectedImage;
@synthesize delegate, selectedImage, spacerBottom, currentIndex;

其他说明,此确实中断:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage release];
//objc[55541]: FREED(id): message release sent to freed object=0x59245b0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

正如这样做

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage autorelease];
//objc[55403]: FREED(id): message autorelease sent to freed object=0x59b54c0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

所以确实以下:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage release];
//objc[55264]: FREED(id): message release sent to freed object=0x592c9a0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

所以这样做

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage autorelease];
//objc[55635]: FREED(id): message release sent to freed object=0x5b305d0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

For some reason, the retain/release behavior in the following code has me completely baffled.

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

This should break but does not. Why? I thought imageNamed autoreleased itself which means the release here is redundant and should break when the autorelease occurs.

Here are snippets relevant to selectedImage from the .h and .m files:

@property (nonatomic, readonly) UIImage *selectedImage;
@synthesize delegate, selectedImage, spacerBottom, currentIndex;

Other notes, this does break:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage release];
//objc[55541]: FREED(id): message release sent to freed object=0x59245b0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

As does this:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];
[selectedImage autorelease];
//objc[55403]: FREED(id): message autorelease sent to freed object=0x59b54c0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

And so does the following:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage release];
//objc[55264]: FREED(id): message release sent to freed object=0x592c9a0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

And so does this:

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage autorelease];
[selectedImage autorelease];
//objc[55635]: FREED(id): message release sent to freed object=0x5b305d0
//Program received signal:  “EXC_BAD_INSTRUCTION”.

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

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

发布评论

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

评论(4

带刺的爱情 2024-09-10 00:20:08

-imageNamed:返回一个自动释放的图像,正如 deanWombourne 所说,它将在未来的某个时间自动释放(确切时间未定义)。

它没有像您可能习惯的那样尽早自动释放的原因是 -imageNamed 还缓存了它返回的图像。缓存正在保留图像。

所以本质上,保留周期是这样的:

  • -imageNamed:被调用,
    • 系统分配并初始化一个映像——retain count = 1;
    • 系统缓存图像 -- 保留计数 = 2;
    • 系统自动释放镜像并返回给您——retain count = 1; (理论上,该镜像的保留计数仍为2,因为自动释放池尚未释放它)。
  • 您对图像调用release——保留计数应该为0并且该对象应该被释放。
  • 在将来的某个时刻(在运行循环结束时),自动释放池应该释放图像,并且会崩溃,因为你已经过度释放了它。

如果不释放它,缓存将继续保留图像,直到释放它为止,例如发生内存警告时。因此,当您使用 imageNamed 获取图像时,它不会被释放,直到缓存被清除。

希望这能解决问题。

-imageNamed: returns an autoreleased image, which, as deanWombourne says, will be autoreleased at some time in the future (the exact time is undefined).

The reason it's not being autoreleased as early as you are perhaps used to is that -imageNamed also caches the image it returns. The cache is retaining the image.

So essentially, the retain cycle is something like this:

  • -imageNamed: called,
    • System allocs and init's an image -- retain count = 1;
    • System caches image -- retain count = 2;
    • System autoreleases image and returns to you -- retain count = 1; (theoretically, the image still has retain count of 2, because the auto release pool has not yet released it).
  • you call release on the image -- retain count should be 0 and the object should be deallocated.
  • At some point in the future (at the end of the run loop), the auto release pool should release the image, and will crash because you have over released it.

If you do not release it, the cache will continue to retain the image until it releases it, for instance when a memory warning occurs. So when you get an image using imageNamed, it doesn't get deallocated, until the cache is purged.

Hope this clears things up.

我一向站在原地 2024-09-10 00:20:08

奇怪又奇怪,是的。但也并非完全无法解释。这就是我认为正在发生的事情。

你是对的; imageNamed: 返回一个自动释放的对象。这意味着它会在将来的某个时候被释放,所以你立即调用它的release不会导致错误——release不是通灵的,它不知道自动释放池也会释放它!

如果您让代码运行,自动释放池最终将尝试再次释放它,然后您将收到您期望的错误。

您实际上已经回答了我们自己的问题 - 您说“应该在自动释放发生时中断”,这是绝对正确的,当自动释放发生时,它会中断:)

其他示例中断是因为您通过调用它们来强制释放发生直接或做足够的事情触发自动释放池运行并为您调用释放。 (你无法预测自动释放池何时运行,你只能知道在运行循环中的某个时刻,自动释放的东西可能会被释放。)

Odd and wierd, yes. But not completely inexplicable. this is what I think is happening.

You're correct; imageNamed: returns an autoreleased object. this means that it's going to get released sometime in the future so you calling release on it straight away won't cause an error - release isn't psychic, it doesn't know that an autorelease pool is also going to release it!

If you left your code running the autorelease pool will eventually try to release it again and then you will get the error you're expecting.

You've actually answered our own question - you say 'should break when the autorelease occurs' which is absolutely correct, when the autorelease occurs, it will break :)

The other examples break because you're forcing releases to happen by either calling them directly or doing enough stuff that the autorelase pool is triggered to run and calls release for you. (You can't predict when the autorelease pool will run, you can just know that at some point in your run loop, autoreleased things maight be released.)

遇见了你 2024-09-10 00:20:08

你说“这应该打破”

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

你错了。

如果 UIImage 是你我会编写并从我们的 Cocoa 书中学习编写的那种类的实例,它可能会崩溃,但我们没有编写它,所以我们不应该猜测它的实现。

UIImage 的工作原理是一个实现细节,而不是您关心的问题。你所知道的是,如果你遵守规则,你应该能够期望它起作用,我相信这些规则现在被称为 NARC,而你在这里还没有这样做。如果您使用不当,任何物体都不会保证“损坏”。您不能指望对象在使用完毕后会被释放——这不是内存管理契约的一部分。

并非所有 Apple 的对象都像教科书类/实例一样工作 - 实际上,对象可能会被缓存、重用、回收,甚至根本不是对象。

别担心,遵守规则。

You say that "This should break"

selectedImage = [UIImage imageNamed:@"icon_72.png"];
[selectedImage release];

You are wrong.

It probably would break if UIImage was an instance of the kind of Class you and i would write and learnt to write from our Cocoa books, but we didn't write it so we shouldn't guess at it's implementation.

How UIImage works is an implementation detail and not your concern. All you know is that you should be able to EXPECT it to work if you follow the rules, which i believe are now being referred to as NARC, and which you haven't done here. Nowhere are objects guaranteed to 'break' if you use them incorrectly. You cannot count on Objects being deallocated when you are thru with them - that isn't part of the memory management contract.

Not all of Apple's objects work like text book class/instances - in reality, objects may be cached, reused, recycled or not even be objects at all.

Don't worry about it, follow the rules.

偏爱自由 2024-09-10 00:20:08

当我创建此类别时:

@implementation UIImage (ReleaseChecks)

+ (id)allocWithZone:(NSZone *)zone
{
    id o = [super allocWithZone:(NSZone *)zone];
    NSLog(@"Image post-ALLOC: 0x%x",
                (unsigned int)o );
    return o;
}

- (id)autorelease
{
    NSLog(@"Image pre-AUTORELEASE: 0x%x; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    return [super autorelease];
}

- (void)release
{
    NSLog(@"Image pre-RELEASE: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super release];
}

- (void)dealloc {
    NSLog(@"Image pre-DEALLOC: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super dealloc];
}

当使用 +imageNamed: 分配时,似乎不会调用 -autorelease。

然而,当我使用 +imageNamed: 创建了一大堆这些,然后收到内存警告时,我可以看到它们全部释放和释放。这是在 iPhone Simulator 4.0 上测试的。

When I create this category:

@implementation UIImage (ReleaseChecks)

+ (id)allocWithZone:(NSZone *)zone
{
    id o = [super allocWithZone:(NSZone *)zone];
    NSLog(@"Image post-ALLOC: 0x%x",
                (unsigned int)o );
    return o;
}

- (id)autorelease
{
    NSLog(@"Image pre-AUTORELEASE: 0x%x; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    return [super autorelease];
}

- (void)release
{
    NSLog(@"Image pre-RELEASE: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super release];
}

- (void)dealloc {
    NSLog(@"Image pre-DEALLOC: 0x%x\n; Retain Count %u",
                (unsigned int)self,
                (unsigned int)[self retainCount]
                );
    [super dealloc];
}

It appears that -autorelease is not called when allocated with +imageNamed:.

However, when I have created a whole bunch of these with +imageNamed: and then later get a memory warning, I can see them all release and dealloc. This was tested on iPhone Simulator 4.0.

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