如何处理@synthesized的版本保留属性?

e.J*_*mes 65 compiler-construction memory-management properties objective-c

我对Objective-C中的合成属性有一些疑问.完整列表如下,但基本问题是:编译器如何确保正确释放合成属性的ivars,即使我的代码可能包含或不包含dealloc中的release方法?

注意:我决定不将这些问题作为单独的问题发布,因为它们密切相关,并且因为有一些现有的问题涉及到个别问题,而没有真正了解问题的核心.

有些类似的问题:


设置:考虑具有单个属性的类:

@interface Person : NSObject
{
    NSString * name;
}
@property (nonatomic, retain) name;
@end
Run Code Online (Sandbox Code Playgroud)

问题#1:最基本的案例:

@implementation Person
@synthesize name;
@end
Run Code Online (Sandbox Code Playgroud)

通过这种设置,我假设name每当一个Person对象被释放时它将自动释放.在我看来,编译器只是插入[name release]dealloc方法中,就像我自己键入它一样.那是对的吗?


问题2:如果我选择dealloc为这个类编写我自己的方法,并且我省略了一个调用[name release],那会泄漏吗?

@implementation Person
@synthesize name;
- (void)dealloc { [super dealloc]; }
@end
Run Code Online (Sandbox Code Playgroud)

问题3:如果我选择dealloc为这个类编写我自己的方法,并且我包含一个调用[name release],那会导致双重释放,因为@synthesize已经为我处理了它吗?

@implementation Person
@synthesize name;
- (void)dealloc { [name release]; [super dealloc]; }
@end
Run Code Online (Sandbox Code Playgroud)

问题4:如果我选择为这个类编写我自己的属性访问器,但是我编写自己的dealloc方法,会name被泄露吗?

@implementation Person
@dynamic name;
- (void)setName:(NSString *)newName
{
    [newName retain];
    [name release];
    name = newName;
}
@end
Run Code Online (Sandbox Code Playgroud)

问题5:我有一种感觉,(根据经验),其没有上述情形会导致泄漏或双版本,因为该语言的设计,以避免它们.当然,这提出了"如何?"的问题.编译器是否足够智能以跟踪每个可能的情况?如果我要做以下事情该怎么办(注意这是一个荒谬的例子,只是为了说明我的观点):

void Cleanup(id object) { [object release]; }

@implementation Person
@synthesize name;
- (void)dealloc { Cleanup(name); }
@end
Run Code Online (Sandbox Code Playgroud)

将这种欺骗编译器将添加其他[name release]dealloc方法?

ken*_*ytm 57

Q1:

@synthesize不修改-dealloc为您服务.你必须-releasename你自己.

Q2:

是的,它会泄漏.与Q1相同的原因.

Q3:

不,它不会双重释放.与Q1相同的原因.

Q4:

是的,它会泄漏.与Q1相同的原因.

Q5:

不,它不会双重释放.与Q1相同的原因.


您可以通过覆盖来自行检查-retain,-release-dealloc报告发生的情况.

#import <Foundation/Foundation.h>

@interface X : NSObject {}
@end
@implementation X
-(oneway void)release {
        NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1);
        [super release];
}
-(id)retain {
        NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1);
        return [super retain];
}
-(void)dealloc {
        NSLog(@"Dealloc %p", self);
        [super dealloc];
}
@end

@interface Y : NSObject {
        X* x;
}
@property (nonatomic, retain) X* x;
@end
@implementation Y
@synthesize x;
- (void)dealloc { [x release]; [super dealloc]; }
@end

int main () {
        NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
        Y* y = [[Y alloc] init];
        X* x = [[X alloc] init];
        y.x = x;
        [y release];
        [x release];
        [pool drain];                                                    
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

在Q1,Q2和Q4中,最后-retainCount一个x是1,所以有泄漏,在Q3和Q5中,最后一个-retainCount是0并被-dealloc调用,所以没有泄漏.

  • 谢谢你的详细解答.我很高兴我问过! (2认同)

Dav*_*ave 17

关于属性Objective-C文档:

的dealloc

声明的属性从根本上取代了访问器方法声明; 在合成属性时,编译器仅创建任何缺少的访问器方法.没有与dealloc方法的直接交互 - 不会自动为您释放属性.但是,声明的属性提供了一种交叉检查dealloc方法实现的有用方法:您可以在头文件中查找所有属性声明,并确保释放未标记为assign的对象属性,并标记为assign的对象属性为没有发布.

这基本上回答了你的所有问题.


Dan*_*Ray 8

简单而通用的规则:如果分配,保留或复制对象,则必须释放它.

当您retain@synthesize语句中使用setter语义设置时,您要求编译器为您构建一个调用retain该对象的setter .没有更多,没有更少.而且由于你保留了那个对象(即使它是通过神奇的自动生成代码),你必须释放它,并在哪里发布它-(void)dealloc.

  • +1这是一个很好的(并且经常被引用)规则.许多人(包括我自己,当我提出这个问题时都回来)没有意识到在财产声明中指定"保留"或"复制"仍然符合条件.我认为问题在于措辞:"我*保留了价值吗?不,编译器的自动代码为我做了.哎呀." (4认同)