【问题标题】:Releasing a property (Objective-C)释放属性(Objective-C)
【发布时间】:2009-05-09 13:32:56
【问题描述】:

我有一个@property,它的定义如下:

@property(非原子,保留)名称;

在一个函数中,我解析一些 xml 并设置 name 属性。 我的问题是我应该在保留新实例之前明确释放以前保留的实例吗?

例如:

myObj.name = [otherObj getName]; // 保留计数 +1

..

myObj.name = [otherObj getName]; // 这是一个名字的新实例,之前的名字是否被释放了?

【问题讨论】:

    标签: objective-c iphone


    【解决方案1】:

    在综合属性设置器中,代码执行的操作大致与此类似(我们将 name 作为属性名称,_name 将作为它所引用的实例变量):

    - (void) setName: (NSString *) newValue
    {
      if ( newValue == _name )
        return;
    
      [newValue retain];
      [_name release];
      _name = newValue;
    }

    现在,这显示了根据您上面的属性声明会发生什么。根据该属性的其他可能属性,该函数将使用 [newValue copy] 而不是 [newValue retain](如果指定了 'copy' 属性),或者将全部包装在 @synchronized(self) 块中(如果 ' NOT 提供了 nonatomic' 属性)。

    我还应该注意,由于您的属性是指实现 NSCopying 协议的 NSString,因此您应该真正使用复制而不是保留,即:

    @property (nonatomic, copy) NSString * name;
    

    这将导致合成的 setter 使用 -copy 而不是 -retain,当您实际传递 NSMutableString 对象时,这会更安全。一个不可变的字符串最终只会被-copy 调用保留,而一个可变的字符串会创建一个新的不可变副本。不这样做意味着字符串本身可以在传递到 setter 后更改,在对象不知情的情况下更改值。

    【讨论】:

    • 即使您希望能够更改 NSMutableString,您也需要使用对新值执行 mutableCopy 的设置器来覆盖合成设置器。这样原件是安全的,您可以根据需要/想要更改字符串的副本。
    • 是的,您也可以将您的属性定义为 NSMutableString。另外值得指出的是:你不能使用 [str isKindOfClass: [NSMutableString class]] 来检查一个 NSString 是否真的是一个 NSMutableString,因为 NSString 是一个“类集群”,这意味着你实际上得到了一个实例NSString subclass,它恰好也是一个 NSMutableString 子类。你最好的选择是使用 -mutableCopy,如果接收者已经是可变的,它将保留。
    【解决方案2】:

    如果您已经为您的属性合成了访问器(使用 @synthesize 指令),它们将在属性被重新分配时释放支持该属性的 ivar。您可能想要显式释放 ivar 的唯一时间是当您的对象被释放时。因此,您的 dealloc 方法可能如下所示:

    - (void)dealloc {
      [name release];
      // other cleanup here
      [super dealloc];
    }
    

    【讨论】:

    • 基本上,属性只是调用 getter 和 setter 的简写。当你设置属性时,你的 setter 中发生的任何事情都会发生。在保留和复制属性的综合设置器中,它将释放旧对象并保留(或复制)新对象。
    • @chuck 是的,我知道。这就是为什么我指定该属性只要被合成就被管理。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    相关资源
    最近更新 更多