0

直到昨天,我还以为我理解了属性内存管理的工作原理,但后来我用 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 它?My@property设置为retain(copy也一样),所以当我这样做时self.myRetainProperty = X,X 的保留计数增加了(它归自己所有),不是吗?

4

4 回答 4

2

release你应该让 setter 为你做释放,所以删除对in的调用dealloc

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

    [super dealloc];
}

这是因为 setter 将被合成为:

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

当您通过时,这将按需要工作nil

于 2013-02-08T14:14:08.063 回答
1

你不需要做

[self.observedDictionary release]

self.observedDictionary=nil;

这样就足够了,因为这是一个属性,它会自动将 release 发送到以前的值

self.observedDictionary=nil;
于 2013-02-08T14:13:29.180 回答
1

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

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

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

另请注意,因此,您永远不应该释放这样的属性。如果您这样做,支持 ivar 可能会被释放,并且消息传递它(release由访问者将属性设置为nil之后)可能会崩溃。

于 2013-02-08T14:14:47.577 回答
0

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

通过调用

[self.observedDictionary release];

您实际上正在通过定义为的访问器方法

- (NSDictionary *)observedDictionary;

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

更具体地说,转移所有权的方法名称的约定是以copymutableCopy或开头。allocnew

一些例子

在这里,我使用了一个并不意味着所有权转让的名称,所以我收到了警告

- (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:(不要转让所有权)

- (id)object;
{
  return [[[NSObject alloc] init] autorelease];
}

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

- (id)newObject;
{
  return [[NSObject alloc] init];
}

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

[self.object release]; //=> Produced warnings

并展示最后一个示例 - 释放一个暗示所有权转移的对象及其名称

[self.newObject release]; //=> No Warning
于 2013-02-08T14:29:08.607 回答