Ios 内存管理和属性(init/dealloc)

Ios 内存管理和属性(init/dealloc),ios,memory-management,properties,Ios,Memory Management,Properties,直到昨天,我还以为我了解了属性内存管理的工作原理,但后来我用XCode运行了一个“分析”任务,并得到了大量“这个对象在这里不是自己的”。下面是一个简单的示例,描述了我的问题: MyObservingObject.h: @interface MyObservingObject : NSObject @property(nonatomic, retain) NSMutableDictionary *observedDictionary; -(id)initWithDictCapacity:(int)

直到昨天,我还以为我了解了属性内存管理的工作原理,但后来我用XCode运行了一个“分析”任务,并得到了大量“这个对象在这里不是自己的”。下面是一个简单的示例,描述了我的问题:

MyObservingObject.h:

@interface MyObservingObject : NSObject
@property(nonatomic, retain) NSMutableDictionary *observedDictionary;
-(id)initWithDictCapacity:(int)capacity;
@end
MyObservingObject.m:

@synthesize observedDictionary;

-(id)initWithDictCapacity:(int)capacity {
    self = [super init];
    if (self) {
        self.observedDictionary = [[[NSMutableDictionary alloc] initWithCapacity:capacity] autorelease];
    }
    return self;
}

- (void)dealloc {
    // The following line makes the Analize action say :
    // "Incorrect decrement of the reference count of an object that is not owned at this point by the caller"
    [self.observedDictionary release], self.observedDictionary=nil;

    [super dealloc];
}
我不明白的是,为什么我不调用
release
就离开这个属性?我的
@property
设置为
retain
copy
也这么做),所以当我做
self.myRetainProperty=X
时,X的retain计数增加了(它归self所有),不是吗?

你不需要这么做

[self.observedDictionary release]
以前

self.observedDictionary=nil;
这就足够了,因为这是一个属性,它会自动将release发送到上一个值

self.observedDictionary=nil;
你不需要这么做

[self.observedDictionary release]
以前

self.observedDictionary=nil;
这就足够了,因为这是一个属性,它会自动将release发送到上一个值

self.observedDictionary=nil;

您应该让setter为您执行释放,因此在
dealloc
中删除对
release
的调用:

- (void)dealloc {
    self.observedDictionary=nil;

    [super dealloc];
}
这是因为setter将被合成为如下内容:

- (void)setObject:(id)object
{
    [object retain];
    [_object release];
    _object = object;
}

当您传入
nil

时,它将根据需要工作。您应该让setter为您执行释放操作,因此在
dealloc
中删除对
release
的调用:

- (void)dealloc {
    self.observedDictionary=nil;

    [super dealloc];
}
这是因为setter将被合成为如下内容:

- (void)setObject:(id)object
{
    [object retain];
    [_object release];
    _object = object;
}

当您传入
nil
时,它将按需要工作。它确实会增加,但当您将其设置为
nil
时,setter方法首先释放backing实例变量,然后才保留并分配新值。因此,将属性设置为
nil
就足够了,但是将ivar设置为
nil
会泄漏内存

为了更好地理解:自动生成的保留setter的典型实现相当于

- (void)setFoo:(id)foo
{
    if (_foo != foo) {
        [_foo release];
        _foo = [foo retain];
    }
}

还要注意,因此,您永远不应该发布这样的属性。如果您这样做,支持ivar可能会被解除分配,并且消息传递(访问器在将属性设置为
nil
后释放它)可能会崩溃。

它确实会增加,但当您将其设置为
nil
时,setter方法首先释放支持实例变量,只有这样,它才能保留并分配新值。因此,将属性设置为
nil
就足够了,但是将ivar设置为
nil
会泄漏内存

为了更好地理解:自动生成的保留setter的典型实现相当于

- (void)setFoo:(id)foo
{
    if (_foo != foo) {
        [_foo release];
        _foo = [foo retain];
    }
}

还要注意,因此,您永远不应该发布这样的属性。如果您这样做,支持ivar可能会被解除分配,并且消息传递(访问器在将属性设置为
nil
之后释放它)可能会崩溃。

编译器警告的原因是因为您检索对象的方式

打电话

[self.observedDictionary release];
实际上,您正在使用定义为

- (NSDictionary *)observedDictionary;
这将返回您的对象,但由于
observedDictionary
的命名,编译器假定没有所有权转移,例如,被调用方不必释放此对象,除非他们采取进一步的保留。正因为如此,编译器认为您将通过释放一个您实际上并不拥有的对象来进行过度扩展

更具体地说,转移所有权的方法名称的约定是以
copy
mutableCopy
alloc
new
开头

一些例子 在这里,我使用了一个并不意味着所有权转移的名称,所以我得到了一个警告

- (id)object;
{
  return [[NSObject alloc] init];
}
//=> Object leaked: allocated object is returned from a method whose name ('object') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'.  This violates the naming convention rules given in the Memory Management Guide for Cocoa
修正1:(不转让所有权)

修正2:(使名称更合适)

有了这些知识,我们可以了解命名约定,我们可以看到下面的说法是错误的,因为我们不拥有返回的对象

[self.object release]; //=> Produced warnings
最后一个示例是释放一个对象,该对象的名称意味着所有权转移

[self.newObject release]; //=> No Warning

编译器警告的原因是您检索对象的方式

打电话

[self.observedDictionary release];
实际上,您正在使用定义为

- (NSDictionary *)observedDictionary;
这将返回您的对象,但由于
observedDictionary
的命名,编译器假定没有所有权转移,例如,被调用方不必释放此对象,除非他们采取进一步的保留。正因为如此,编译器认为您将通过释放一个您实际上并不拥有的对象来进行过度扩展

更具体地说,转移所有权的方法名称的约定是以
copy
mutableCopy
alloc
new
开头

一些例子 在这里,我使用了一个并不意味着所有权转移的名称,所以我得到了一个警告

- (id)object;
{
  return [[NSObject alloc] init];
}
//=> Object leaked: allocated object is returned from a method whose name ('object') does not start with 'copy', 'mutableCopy', 'alloc' or 'new'.  This violates the naming convention rules given in the Memory Management Guide for Cocoa
修正1:(不转让所有权)

修正2:(使名称更合适)

有了这些知识,我们可以了解命名约定,我们可以看到下面的说法是错误的,因为我们不拥有返回的对象

[self.object release]; //=> Produced warnings
最后一个示例是释放一个对象,该对象的名称意味着所有权转移

[self.newObject release]; //=> No Warning

谢谢!我完全明白:)!但是
[\u myProperty release],\u myProperty=nil
是正确的,对吗?对于Ivarth,这个答案虽然正确,但不能说明编译器警告的实际原因。需要理解的更大的问题是,用户正在对一个他们不拥有的对象调用
release
——请参阅我的扩展答案。@Paul.s我的答案,解释意味着释放的对象不属于调用方。OP需要通过一个例子来理解这个问题,而不必使用“技术”或律师语言来解释。非常感谢!我完全明白:)!但是
[\u myPrope