为什么我不能使用getter在objective-c中释放属性?

时间:2022-09-07 09:29:04

I was told by a fellow * user that I should not use the getter method when releasing a property:

一个*用户告诉我,我在发布属性时不应该使用getter方法:

@property(nonatmic, retain) Type* variable;
@synthesize variable;

// wrong
[self.variable release]; 

// right
[variable release]; 

He did not explain in detail why. They appear the same to me. My iOS book said the getter on a property will look like this:

他没有详细解释原因。它们在我看来是一样的。我的iosbook说属性的getter是这样的:

- (id)variable {
    return variable;
}

So doesn't this mean [self variable], self.variable, and variable are all the same?

这不是说[self variable] self。变量和变量都一样吗?

4 个解决方案

#1


4  

A typical getter will look more like this:

一个典型的getter应该是这样的:

- (id)variable {
   return [[variable retain] autorelease];
}

So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).

如果你用[self]变量释放]你有一个额外的保留和自动释放,当你只是想释放对象的时候,你并不需要它,这会导致对象在必要的时候被释放(当自动释放池被耗尽)。

Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.

通常,你要么用self。variable = nil的好处是,它还将变量设置为nil(避免由于悬空指针而导致的崩溃),或者[variable release],如果您的setter有自定义逻辑,它是最快的,在dealloc方法中可能更合适。

#2


13  

For a retained property with no custom accessor, you can release the object by:

对于没有自定义访问器的保留属性,可以通过以下方式释放对象:

self.variable = nil;

This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.

它的作用是将ivar(如果您只声明了属性,那么它可能不会被称为'variable')设置为nil并释放之前的值。

As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.

正如其他人指出的,可以直接释放ivar(如果可用),也可以使用上面的方法——您不能做的是对从getter返回的变量调用release。

#3


9  

You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].

您可以选择编写自定义getter行为,这可能导致完全不同的行为。因此,您不能总是假设[变量release]的结果与[self]相同。变量释放)。

As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!

同样,您也可以编写自定义属性,而无需使用专有的ivar支持它们……如果您开始从getters返回的引用中释放对象,它可能会变得混乱。

There may be additional reasons that I'm unaware of...

可能还有其他我不知道的原因……

#4


4  

not all getters take this form:

并不是所有的getter方法:

- (id)variable { return variable; }

...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.

…那只是最原始的形式。属性本身应该建议更多的组合,从而改变实现。上面的原语访问器不考虑与内存管理、原子性或复制语义结合使用的习惯用法。在子类覆盖中,实现也是脆弱的。

some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.

下面是一些非常简单的例子;在实现变得相当复杂的实际程序中,事情显然变得更加复杂。

1) the getter may not return the instance variable. one of several possibilities:

1) getter可能不会返回实例变量。的几种可能性:

- (NSObject *)a { return [[a copy] autorelease]; }

2) the setter may not retain the instance variable. one of several possibilities:

2) setter可能不会保留实例变量。的几种可能性:

- (void)setA:(NSObject *)arg
{
  ...
  a = [arg copy];
  ...
}

3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:

3)您最终会在整个程序中实现内存管理,这使得维护变得困难。类的语义(以及它如何处理实例变量的ref计数)应该保留到类中,并遵循预期结果的约定:

- (void)stuff:(NSString *)arg
{
    const bool TheRightWay = false;
    if (TheRightWay) {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [string release];
        // - or -
        NSMutableString * string = [[arg mutableCopy] autorelase];
        [string appendString:@"2"];
        self.a = string;
    }
    else {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [self.a release];
    }
}

failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.

如果不遵循这些简单的规则,代码就很难维护和调试,扩展起来也很痛苦。

so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.

简而言之,你想让你的程序易于维护。直接在属性上调用release需要您了解类的内部工作环境的很多上下文;这显然是不好的,并且忽略了好的理想。

it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).

它还期望作者/子类/客户端能够准确地知道类如何偏离常规,当问题出现时,这是愚蠢的和耗时的,当问题出现时,您必须重新学习所有的内部细节(他们将在某个时间点)。

those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.

这些是一些关于如何在属性结果上调用release函数的简单示例。许多现实世界的问题都更微妙,也很难定位。

#1


4  

A typical getter will look more like this:

一个典型的getter应该是这样的:

- (id)variable {
   return [[variable retain] autorelease];
}

So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).

如果你用[self]变量释放]你有一个额外的保留和自动释放,当你只是想释放对象的时候,你并不需要它,这会导致对象在必要的时候被释放(当自动释放池被耗尽)。

Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.

通常,你要么用self。variable = nil的好处是,它还将变量设置为nil(避免由于悬空指针而导致的崩溃),或者[variable release],如果您的setter有自定义逻辑,它是最快的,在dealloc方法中可能更合适。

#2


13  

For a retained property with no custom accessor, you can release the object by:

对于没有自定义访问器的保留属性,可以通过以下方式释放对象:

self.variable = nil;

This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.

它的作用是将ivar(如果您只声明了属性,那么它可能不会被称为'variable')设置为nil并释放之前的值。

As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.

正如其他人指出的,可以直接释放ivar(如果可用),也可以使用上面的方法——您不能做的是对从getter返回的变量调用release。

#3


9  

You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].

您可以选择编写自定义getter行为,这可能导致完全不同的行为。因此,您不能总是假设[变量release]的结果与[self]相同。变量释放)。

As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!

同样,您也可以编写自定义属性,而无需使用专有的ivar支持它们……如果您开始从getters返回的引用中释放对象,它可能会变得混乱。

There may be additional reasons that I'm unaware of...

可能还有其他我不知道的原因……

#4


4  

not all getters take this form:

并不是所有的getter方法:

- (id)variable { return variable; }

...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.

…那只是最原始的形式。属性本身应该建议更多的组合,从而改变实现。上面的原语访问器不考虑与内存管理、原子性或复制语义结合使用的习惯用法。在子类覆盖中,实现也是脆弱的。

some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.

下面是一些非常简单的例子;在实现变得相当复杂的实际程序中,事情显然变得更加复杂。

1) the getter may not return the instance variable. one of several possibilities:

1) getter可能不会返回实例变量。的几种可能性:

- (NSObject *)a { return [[a copy] autorelease]; }

2) the setter may not retain the instance variable. one of several possibilities:

2) setter可能不会保留实例变量。的几种可能性:

- (void)setA:(NSObject *)arg
{
  ...
  a = [arg copy];
  ...
}

3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:

3)您最终会在整个程序中实现内存管理,这使得维护变得困难。类的语义(以及它如何处理实例变量的ref计数)应该保留到类中,并遵循预期结果的约定:

- (void)stuff:(NSString *)arg
{
    const bool TheRightWay = false;
    if (TheRightWay) {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [string release];
        // - or -
        NSMutableString * string = [[arg mutableCopy] autorelase];
        [string appendString:@"2"];
        self.a = string;
    }
    else {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [self.a release];
    }
}

failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.

如果不遵循这些简单的规则,代码就很难维护和调试,扩展起来也很痛苦。

so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.

简而言之,你想让你的程序易于维护。直接在属性上调用release需要您了解类的内部工作环境的很多上下文;这显然是不好的,并且忽略了好的理想。

it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).

它还期望作者/子类/客户端能够准确地知道类如何偏离常规,当问题出现时,这是愚蠢的和耗时的,当问题出现时,您必须重新学习所有的内部细节(他们将在某个时间点)。

those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.

这些是一些关于如何在属性结果上调用release函数的简单示例。许多现实世界的问题都更微妙,也很难定位。