代码之家  ›  专栏  ›  技术社区  ›  MrHen

uiimage imagename未正确自动释放

  •  3
  • MrHen  · 技术社区  · 15 年前

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

    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”.
    

    AS 这是:

    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”.
    
    4 回复  |  直到 14 年前
        1
  •  11
  •   Jasarien    15 年前

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

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

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

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

    如果不释放它,则缓存将继续保留图像,直到释放它为止,例如在出现内存警告时。因此,当使用imagename获取图像时,在清除缓存之前,它不会被释放。

    希望这能解决问题。

        2
  •  8
  •   deanWombourne    15 年前

    是的,很奇怪。但并非完全无法解释。这就是我想发生的事情。

    你是对的; imageNamed: 返回自动释放的对象。这意味着它将在将来某个时候被释放,所以你马上调用释放不会导致错误-释放不是精神的,它不知道自动释放池也将释放它!

    如果您将代码留在运行中,自动释放池最终将再次尝试释放它,并且 然后 你会得到你期望的错误。

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

    其他的例子会中断,因为您通过直接调用它们或者做足够多的事情来强制发布,从而触发autorelase池来运行并为您调用release。(您无法预测自动释放池何时运行,您只需知道在运行循环的某一点上,自动释放的东西会被释放。)

        3
  •  0
  •   hooleyhoop    15 年前

    你说“这应该打破”

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

    你错了。

    如果uiimage是你和我从我们的cocoa书中写作和学习写作的类的一个例子,它可能会被打破,但是我们没有写它,所以我们不应该猜测它的实现。

    uiimage如何工作是一个实现细节,而不是您关心的问题。你所知道的是,如果你遵守这些规则,你应该能够期望它能起作用,我相信这些规则现在被称为“毒品”,而你在这里还没有做到。如果不正确地使用对象,就不能保证它们“断裂”。当您遍历对象时,您不能指望它们被释放——这不是内存管理合同的一部分。

    并非所有苹果的对象都像文本书类/实例那样工作——事实上,对象可能被缓存、重用、回收,甚至根本不是对象。

    别担心,遵守规则。

        4
  •  0
  •   henryaz    15 年前

    当我创建此类别时:

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

    当使用+imagename:分配时,似乎未调用-autorelease。

    但是,当我用+imagename创建了一组这样的文件:然后得到一个内存警告时,我可以看到它们全部释放和释放。这是在iPhoneSimulator4.0上测试的。