代码之家  ›  专栏  ›  技术社区  ›  Jason McCreary

Objective-C(iPhone)ivars和内存管理

  •  3
  • Jason McCreary  · 技术社区  · 15 年前

    我正在子类化nsurlconnection,并使用mgtwitterengine作为基础来帮助我开始。这可能无关紧要。但是,我注意到他们的代码中没有使用 @property @synthesize 为了他们的爱。他们将ivar包装在访问器方法中,如下所示:

    - (NSString *)identifier {
      return [[_identifier retain] autorelease];
    }
    

    我的问题分为两部分。首先,效果如何 retain 然后 autorelease 有吗?在我看来 取消 本身,或者更糟的是泄漏。

    其次,如果要将头文件更改为:

    @property (nonatomic, retain, readonly) NSString* _identifier;
    

    并使用 @synthesize indentifier = _identifier ,这难道不需要编写访问器方法就可以做同样的事情吗?

    也许这只是做同样事情的两种不同方式。但我想确保我有正确的理解。谢谢。

    4 回复  |  直到 14 年前
        1
  •  8
  •   FreeAsInBeer Jeff    14 年前

    使用 @synthesize 实际上只创建setter和getter方法。自动为您生成的代码保证使用适当的内存管理,这样您就不必担心了。

    mgtwitterengines使用 return [[ivar retain] autorelease ]实际上是正确的方法。我们来举两个例子。

    假设getter定义如下:

    -(Foo)foo {
        return foo;
    }
    

    然后我们执行以下代码:

    1. bar = [[bar alloc] init]; //条的计数为1。
    2. foo = bar.foo; //foo har保留计数为1(由bar拥有)。
    3. [bar release]; //bar和它的所有ivar都被强制释放!
    4. [foo doSomething]; //这将在上一行释放foo后崩溃。

    如果我们将getter改为:

    -(Foo)foo {
        return [[foo retain] autorelease];
    }
    
    1. bar=[[bar alloc]init]; //条的保留计数为1
    2. Fo=B.Fo; //foo的保留计数为2(一个由bar拥有,一个由autorelease pool拥有)。
    3. [酒吧释放]; //bar和它的所有ivar都被强制释放!
    4. 【foo剂量测定】; //不会崩溃,因为foo仍然存在并且归autorelease池所有。

    希望这能解释为什么您应该总是从所有getter中正确地返回自动释放的对象。重要的是,任何返回值都可以在其父级的释放之后继续存在,因为没有任何类CA可以保证客户端在暴露于野外后将如何处理其值。

        2
  •  3
  •   James Huddleston    15 年前

    “保留”后接“自动释放”的操作与您可能认为的完全相同。它发送对象A retain 然后发送一条消息 autorelease 消息。记住,自动释放对象会将该对象添加到自动释放池中 但还没有释放它 . 自动释放池将发送对象A release 运行循环当前迭代结束时的消息。所以,A 保持 然后 自动复位 本质上说,“确保这个对象一直保持到运行循环的当前迭代结束。”如果需要返回的值保持更长的时间,可以保留它。如果没有,什么都不做,自动释放池将处理它。

    在这种情况下,正在发送的字符串 保持 自动复位 消息是一种属性。它已由父对象保留。所以你可能想知道为什么这个保留和自动释放的事情?好吧,不能保证物体不会释放 _identifier 在运行循环的当前迭代结束之前。考虑这个例子:

    - (NSString *)identifier { return _identifier; }
    
    - (void)aMethod {
        NSString *localId = [self identifier]; // localId refers to _identifier which is only retained by self
        [self methodThatChangesIdentifierAndReleasesItsOldValue];  // self releases _identifier
        NSLog(@"%@", localId); // crash, because localId (old value of _identifier) has been released
    }
    

    在这种情况下,返回的标识符不会被保留并自动释放。这个 NSLog 线路崩溃是因为 localId 引用已释放的字符串。但是,我们用过吗 保持 自动复位 在盖特,不会有碰撞,因为 局部化 直到运行循环的当前迭代结束时才会释放。

    据我所知,你的替代者 identifier 房地产也一样好。它可能不是相同的代码,但效果应该相同。

        3
  •  1
  •   Ole Begemann    15 年前

    苹果很好地解释了这一点 Implementing Accessor Methods .您引用的方法(Apple称为“技术1”)有助于避免错误,如果调用者为Identifier属性分配了一个新值,然后期望检索到的值仍然可用。大多数时候不需要它,但是仅仅返回ivar值就可能导致难以跟踪的错误。

        4
  •  0
  •   jer    15 年前

    一般来说,如果你归还的东西不是你最初拥有的,你会保留然后自动租赁。只有你拥有它才会泄漏 _identifier 保留/分配/etc与发送到该对象的释放/自动释放不匹配。

    其次,是的,如果您没有做一些超出常规样板文件外观的特殊工作,那么通常不需要编写头文件。苹果公司有很好的财产证明文件,我建议如果你仍然模糊,你看看那些。