【问题标题】:Designated Initializer, retain parameters?指定初始化器,保留参数?
【发布时间】:2010-12-07 00:23:34
【问题描述】:

我有以下指定的初始化器:

-(id) initWithName:(NSString*)name;

以及以下默认初始化程序:

-(id) init { return [self initWithName:@"foo"]; }

指定的初始化器接收的对象是什么类型的?发布还是自动发布?

给定以下初始化器:

-(id) init { return [self initWithName:[NSString new]]; }

我会收到一个 retined 对象。默认初始化程序永远没有机会释放它,所以我不应该保留它吗? 现在想象一下,这将是一个不提供便利初始化程序的类而不是 NSString(如 -myClassWithParam:)。我是否需要提供方便的初始化程序来启用就地构造?

【问题讨论】:

    标签: objective-c memory-management


    【解决方案1】:

    初始化器(无论是否指定)都不应该关心它作为参数接收的对象的所有权。如果它想保留对象,它必须复制或保留它,无论参数来自哪里。您指定的初始化程序 initWithName 应在其实现中复制 name 参数。

    NSString 字面量的内存管理是一种特殊情况,因为这些对象永远不会被释放,只会忽略 retainreleaseautorelease

    您的第三个示例有泄漏,因为 name 参数字符串对象从未被释放。

    【讨论】:

    • 更一般地说,没有方法应该关心它接收到的对象的所有权。方法唯一应该依赖的(除非它声称拥有所有权)是参数将在该方法的持续时间内存在。
    • 感谢您的澄清,我自己也想到了这一点,但希望有其他意见。你可以猜到,我对 obj-c 很陌生
    【解决方案2】:

    您应该始终向您的初始化程序发送一个自动释放的对象(或在之后释放它) - 在这种情况下内存管理规则不会改变。

    在你的例子中,我会这样做:

    -(id) init {return [self initWithName:[[NSString new] autorelease]]]}
    

    这将修复您的内存泄漏并仍然允许就地构建。

    但是,通过初始化程序时,您不需要额外的保留 - 您使用 self 所做的一切都很好。通常,+alloc 保留对象一次,-init 方法不再保留。 -init 将被多次调用,因为 [super init] 调用会沿类树向上移动,但对象只应在最终返回给调用者时保留一次 - +alloc 已经为您完成了这项工作。

    但是, 包含 init、copy 或 new 字样的 convenience 方法应该返回一个自动释放的对象。举个例子:

    +(MyObject *)objectWithName:(NSString *)aName {
        return [[[MyObject alloc] initWithName:aName] autorelease];
    }
    

    FWIW,我通常将 -init 作为我指定的初始化程序,所以如果我忘记并将 -init 发送到一个对象(或其他人也这样做),你不会得到垃圾对象。例如:

    -(id)init {
        if (self = [super init]) {
            [self setName:[[NSString new] autorelease]];
    
            myReallyImportantiVar = [[NSArray alloc] init];
            // etc;
        }
        return self;
    }
    
    
    -(id)initWithName:(NSString  *)aName {
        if (self = [self init]) {
            [self setName:aName];
        }
        return self;
    }
    

    这可能效率稍低(当您使用 -initWithName: 时,setName 会被调用两次),但它更安全。

    【讨论】:

    • [[NSString new] autorelease][NSString string] 或只是@"" 的一种混淆方式
    • 我不太喜欢你用初始化器做的事情。具有最少参数计数的 init 方法应该调用具有多个参数的 init 方法,其中您为额外参数传递一个默认变量(可能是 nil)。我会迷失在您使用的练习中,但这可能只是风格问题。 Cocoa 方法是使用我之前描述的机制来实现。您可以在我的下载类中看到一个典型示例:github.com/JoostK/Download-Manager/blob/master/…(第 61-119 行)
    • @Nikolai 关于保留自我,我正在回答问题的一部分,他询问指定的初始化程序是否应该保留由 init 返回的对象。我也知道 [NSString string] 和 @"",但我试图避免使用字符串文字和便利方法,因为这就是 OP 感到困惑的地方。也许我应该使用不同的课程。
    • @iKenndac 据我了解,Johannes 从来没有谈论保留要初始化的对象,而只是谈论保留字符串参数。
    猜你喜欢
    • 1970-01-01
    • 2023-04-09
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 2014-07-27
    • 2020-08-10
    • 2015-02-24
    相关资源
    最近更新 更多