2010-10-24 63 views
3

我是NSURLConnection的子类,并使用MGTwitterEngine作为基础来帮助我开始。这可能是无关紧要的。然而,我在他们的代码中发现他们不使用他们的ivars @property@synthesize。他们已经用看起来像这样的访问器方法包装了ivars:Objective-C(iPhone)ivars和内存管理

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

我的问题是两部分。首先retainautorelease有什么关系?在我看来,它会取消本身,或更糟糕的是泄漏。

其次,如果我改变头文件有:

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

并用@synthesize indentifier = _identifier,就不会这样做同样的事情的访问方法,而不必写呢?

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

回答

8

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

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

假设一个getter被定义为这样的:

-(Foo)foo { 
    return foo; 
} 

然后我们执行这个代码:1.

  • foo = bar.foo; // foo的哈日的

    1. bar = [[bar alloc] init]; //酒吧已经aretain计数保留数为1(由酒吧拥有)。
    2. [bar release]; //酒吧和它的所有ivars都被释放出来!
    3. [foo doSomething]; //自上一行发布foo以后,这会崩溃。

    如果我们不是改变吸气这样:

    -(Foo)foo { 
        return [[foo retain] autorelease]; 
    } 
    
    1. bar = [[bar alloc] init]; //栏有1个
    2. foo = bar.foo; // FOO的保留数为2挡计数(一体的独资由酒吧,1由自动释放池拥有)。
    3. [bar release]; //酒吧和它的所有ivars都被释放出来!
    4. [foo doSomething]; //不会崩溃,因为foo还活着并且被autorelease池所有。

    希望这解释了为什么你应该总是从你所有的获得者中正确地返回自动释放的对象。重要的是,任何回报价值都可以在其父母的重新分配后生存下来,因为没有阶级可以保证一旦客户暴露于野外,客户将如何处理这些价值。

  • +0

    这是有道理的。感谢您的详细解释。一个方面的问题,如果我的一个ivars是对'delegate'的引用,我不希望这样做,而是倾向于使用具有'assign'属性的'@ property'。也就是说,我不应该在引用类对象时调用'retain' /'autorelease',对吧?只有我的课程拥有并允许访问者。 – 2010-10-24 17:46:57

    +0

    @Jason:对,代表不应该由内存管理,因此他们只需执行'return delegate'。如果属性是'copy',那么在mutator方法中执行'ivar = [arg copy]',在getter方法中执行'return [[ivar retain] autorelease]'。 – PeyloW 2010-10-25 13:04:02

    0

    一般来说,如果你正在返回一些你并不拥有第一名的东西,那么一般会保留然后autoreleases。它只会泄漏,如果你拥有_identifier,并且保留/分配等与发送到该对象的释放/自动释放不匹配。

    其次,是的,你通常不必写头,如果你没有做一些特殊的东西超出一般样板看起来像。苹果有很好的文件记录,如果你仍然模糊不清,你可以看看这些文件。

    +1

    即使您确实“拥有”了您要返回的内容,仍然保留/ autorelease以保证该对象在调用者范围内有效。返回属性的对象可能不一定是那么长。 – 2010-10-24 16:16:05

    3

    保留,然后自动释放不正是你可能认为它。它发送该对象的retain消息,然后将它发送一个autorelease消息。请记住,自动释放对象将该对象添加到自动释放池但不释放它尚未。自动释放池将在运行循环的当前迭代结束时向对象发送release消息。因此,随后autorelease一个retain实际上是说,“确保这个对象总是在那里,直到运行循环的当前迭代的结束。”如果您需要返回的值更长的时间,可以保留它。如果不是,则不执行任何操作,autorelease池将处理它。

    在这种情况下,发送的字符串retainautorelease是属性。它已被父对象保留。所以你可能想知道为什么这样保留和自动释放东西呢?那么,不能保证该对象在运行循环的当前迭代结束之前不会释放_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引用释放的字符串。但是,如果我们在吸气剂中使用了retainautorelease,则不会发生崩溃,因为localId只有在运行循环的当前迭代结束时才会释放。

    据我所知,您更换identifier属性将是一样好。它可能不是相同的代码,但效果应该是相同的。

    1

    苹果在Implementing Accessor Methods解释了这一点。您引用的方法(由Apple命名为“Technique 1”)有助于避免错误,如果调用方为标识符属性分配新值并希望检索值仍然可用。大部分时间不需要它,但只是返回伊娃价值可能导致难以追踪的错误。