iOS - 我很困惑这里是如何处理内存的?

Posted

技术标签:

【中文标题】iOS - 我很困惑这里是如何处理内存的?【英文标题】:iOS - I'm confused how memory is being handled here? 【发布时间】:2011-09-27 13:04:02 【问题描述】:

UIImage API 参考文档:- initWithContentsOfFile: 使用指定文件的内容初始化并返回图像对象。

- (id)initWithContentsOfFile:(NSString *)path

参数路径 文件的路径。此路径应包含标识图像数据类型的文件扩展名。返回值 一个已初始化的 UIImage 对象,如果方法无法找到文件或从其内容初始化图像,则为 nil

考虑到这种情况,假设我有一个类,它可以是任何类的扩展。以 UIImage 为例。

@interface myImage : UIImage

    BOOL isDefaultSet;


-(id)initWithDefaultImage;

@end

@implementation myImage


-(id)initWithDefaultImage

    NSString *path = [[NSBundle mainBundle] pathForResource:@"someInvalidImage" ofType:@"png"];

    idDefaultSet = YES;

    return [self initWithContentsOfFile:path];


@end


//somewhere in other class:

NSString *path = [[NSBundle mainBundle] pathForResource:@"someInvalidImage" ofType:@"png"];

myImage *myObject = [[myImage alloc] initWithDefaultImage];
UIImage *yourObject = [[UIImage alloc] initWithContentsOfFile:path];

现在在这两种情况下,

“alloc”给出“retainCount+1”

如果

initWithDefaultImage/initWithContentsOfFile

由于某些问题返回 nil - 可以说(无效的文件路径),此内存将泄漏为

我的对象/你的对象

即使 allocation 是在 init 之前进行的,也会设置为 nil。

我已经看到许多以这种方式扩展类/接口的实现。我很困惑这里是如何处理内存的?任何人都可以分享对此的看法吗?

【问题讨论】:

我建议遵守约定,让您的课程以大写字符开头。你会让你的生活更轻松(如果你和其他人一起工作,你会避免被侮辱和殴打;-) 亲爱的 DarkDust.. 我只是在讨论这个问题。请不要这么苛刻..! 我认为 DarkDust 是在开玩笑,仅此而已。不过,DarkDust 是正确的,正如我通过艰难的方式了解到的那样,类应该大写,ivars 和方法以小写开头。 【参考方案1】:

如果 [super init] 返回 nil,则返回 nil。因此控件从方法返回,并且 if (someInitializingFailed) 块将永远不会被执行,并且内存将被泄漏,因为在调用“initWithFoo”之前已经执行了 alloc

如果[super init]返回nil,则super的init已经自行清理并释放了alloc分配的内存。

来自Handling Initialization Failure:

您应该只在发生故障时调用 self 的 release 方法。如果你从调用超类的初始化程序得到 nil,你不应该也调用 release。

【讨论】:

【参考方案2】:

通常对应的初始化器在返回nil之前释放self(新对象),如:

- (id)initWithFoo

    self = [super init];
    if (!self) return nil;

    if (someInitializingFailed) 
        [self release];
        return nil;
    

    return self;

您可以假设-[UIImage initWithContentsOfFile:] 正在实现相同的模式。因此,除非 Instruments 确实告诉您存在泄漏,否则您不需要对您的情况进行任何特殊处理。

【讨论】:

在这种情况下也可以看到。如果 [super init] 返回 nil,则返回 nil。因此控件从方法返回,并且 if (someInitializingFailed) 块将永远不会被执行,并且内存将被泄漏,因为在调用“initWithFoo”之前已经执行了 alloc。 如果我替换 -> 返回 [self initWithContentsOfFile:path]; with -> return [super initWithContentsOfFile:path];那么它会是正确的吗? @samfisher 如果[super init] 返回nil,则super 的init 已经自行清理并释放alloc 分配的内存。在other words 中,“你应该只在失败点调用 self 的 release 方法。如果你从调用超类的初始化程序得到 nil ,你不应该也调用 release。” 感谢@albertamg 这就是我正在寻找的解释。您可以将其发布为答案以便我接受吗?【参考方案3】:

您是对的,有时人们会忘记处理这种泄漏。如果我们无法继续初始化,则需要释放分配的内存。

-(id)initWithDefaultImage

    NSString *path = [[NSBundle mainBundle] pathForResource:@"someInvalidImage" ofType:@"png"];
    if (path != nil)
    
        self = [super initWithContentsOfFile:path];
    
    else // cannot proceed with init
    
        [self release];
        self = nil;
    
    return self;

【讨论】:

一开始已经完成了init,怎么调用initWithContentsOfFile呢?

以上是关于iOS - 我很困惑这里是如何处理内存的?的主要内容,如果未能解决你的问题,请参考以下文章

Lua 表在内存中是如何处理的?

MySQL(InnoDB)是如何处理死锁的

面试官:tomcat是如何处理http请求的?

VB.NET 表单变量是如何处理的

源码解析Flink 是如何处理迟到数据

详解MySQL(InnoDB)是如何处理死锁的