【问题标题】:Will assigning nil to a retained property release the object associated to it?将 nil 分配给保留的属性会释放与其关联的对象吗?
【发布时间】:2012-08-16 11:43:39
【问题描述】:

当不在ARC下时,对于下面的代码,

.h

@property (nonatomic, retain) NSString *s;

.m

NSString *m = [NSString stringWithString:@"Hellow, World"];
s = [m retain];

// later on
s = nil; <-- will this release the ref count on the string and hence get the string released?

【问题讨论】:

    标签: ios memory-management memory-leaks nsstring


    【解决方案1】:

    当这样使用时(即通过直接访问实例变量),不,它不会。但是,如果您使用属性的访问器方法([self setS:nil];self.s = nil;),那么可以。

    还要注意释放一个对象和释放它的内存是两件完全不同的事情。一个对象只有在它没有更多的强引用时才会被释放 - i。 e.你有它的最后一个引用,然后你释放它。如果你释放它但它有其他引用(之前被保留),那么它不会被释放,只有它的引用计数会减一。

    此外,如果您有一个保留属性,例如您的示例中的那个,您不能这样做 1. 直接访问底层实例变量,2. 做类似的事情

    NSString *m = [NSString stringWithString:@"Hellow, World"];
    s = [m retain];
    

    为什么?因为第一行根本没有必要——真的,为什么- [NSString stringWithString:]?您正在创建一个常量字符串,然后创建它的精确副本 - 这只是多余的。如果 Cocoa 的设计者是菜鸟,那么这行代码也会浪费内存——同一不可变字符串的两个完全相同的副本。幸运的是,实现 NSString 的人已经为这种情况做好了准备,并让这个方法检查它的参数是否是一个常量,如果是,则不做任何事情就返回它——所以你得到了相同的指针,但是对objc_msgSend 进行了一些额外的调用——这不是你想要的。

    第二行也是错误的 - 同样,您没有按原样使用支持 ivar。此外,该属性被声明为 retain 是有原因的 - 如果您将一个对象设置为您的属性,该对象将由 setter 方法保留 - 无需手动保留它。

    总之,你最好写

    self.s = @"Hello World";
    
    // ...
    
    self.s = nil;
    

    改为。

    【讨论】:

      【解决方案2】:

      做这个操作的正确方法是这样的。

      self.s = [NSString stringWithString:@"Hellow, World"]; // this will ensure that string is retained 
      
      // later on
      self.s = nil; // this will ensure that retain count is reduced. 
      

      NSString 的释放将取决于 iOS AutoreleasePool,因为您正在释放保留计数,下次 GC 运行时它将检查该字符串的总保留计数,如果它没有在其他任何地方使用,那么它将删除该对象。

      【讨论】:

        【解决方案3】:

        所有retain 调用都应与匹配的release 配对。通过分配给nil,您将放弃保留的对象。

        【讨论】:

        • 什么是放弃对象?不发布?
        • @tom 不,您正在丢失指向它的指针,因此您正在泄漏内存。
        • 重要的是要对您retain 的所有对象负责,直到它们被释放,正如@H2CO3 所说,放弃它是一种泄漏形式。
        【解决方案4】:

        在这种情况下,是的,假设您使用该属性并且不直接修改实例变量。如果属性是 strong 而不是 ARC 下的 retain 也是如此。基本上,您的合成属性将如下所示:

        - (void)setPropertyName:(NSString *)value {
          [value retain];
          [_propertyName release];
          _propertyName = value;
        }
        

        因此,如果您为其分配新值,则新值将被保留,旧值将被释放。如果新旧值相同,则基本没有效果。

        注意:请记住,在您的示例代码中,您在分配对象后会保留该对象,因此如果您通过Cocoa memory management policy 访问,您现在拥有该对象的所有权。因此,一旦您设置了该属性,您需要releaseautorelease 对象以避免泄漏(因为使用该属性,该对象也将被它保留)。

        【讨论】:

          【解决方案5】:

          如果obj是一个属性,那么

          self.obj = nil;
          

          实际上会为您发布它。

          但如果不是属性或成员或局部变量

           obj = nil;
          

          那么你将不得不管理释放

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-07-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多