直到昨天我还以为我理解了属性内存管理是如何工作的,但后来我用XCode运行了一个“Analize”任务并获得了很多“这个对象不在这里”。这是一个描述我的问题的简单示例:
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
设置为{ {1}}(retain
做同样的事情),所以当我做copy
时,X的保留计数增加(它由自己拥有),不是吗?
答案 0 :(得分:2)
您应该让设置者为您执行发布,因此请移除release
中对dealloc
的呼叫:
- (void)dealloc {
self.observedDictionary=nil;
[super dealloc];
}
这是因为setter将被合成化为:
- (void)setObject:(id)object
{
[object retain];
[_object release];
_object = object;
}
当您传递nil
时,这将按预期工作。
答案 1 :(得分:1)
你不需要做
[self.observedDictionary release]
之前
self.observedDictionary=nil;
这就足够了,因为这是一个属性,它会自动将释放发送到以前的值
self.observedDictionary=nil;
答案 2 :(得分:1)
确实增加了,但是当你将它设置为nil
时,setter方法首先释放后备实例变量,然后才保留并分配新值。因此,将属性设置为nil
就足够了,将 ivar 设置为nil
泄漏内存。
为了更好地理解:自动生成的保留设置器的典型实现等同于
- (void)setFoo:(id)foo
{
if (_foo != foo) {
[_foo release];
_foo = [foo retain];
}
}
另请注意,因此,您永远不应发布此类属性。如果这样做,可能会取消分配支持ivar,并且在将属性设置为release
之后由访问者发送消息nil
可能会崩溃。
答案 3 :(得分:0)
编译器警告的原因是您检索对象的方式。
致电
[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 :(不转让所有权)
- (id)object;
{
return [[[NSObject alloc] init] autorelease];
}
修复2 :(使名称更合适)
- (id)newObject;
{
return [[NSObject alloc] init];
}
根据这些知识,我们可以看到命名约定,我们可以看到下面的内容是错误的,因为我们不拥有返回的对象
[self.object release]; //=> Produced warnings
并展示最后一个例子 - 发布一个暗示所有权转移的对象,其名称为
[self.newObject release]; //=> No Warning