如何使用@synthesize实现retain setter?

时间:2010-10-13 13:57:31

标签: iphone objective-c memory-management properties retain

标题中有以下内容:

@property (nonatomic, retain) UIView *overlay;

在实施中:

@synthesize overlay;

然后:

UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
self.overlay = tempOverlay;
[tempOverlay release];

上面的tempOverlay变量不是不必要的吗?我不能这样做:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

6 个答案:

答案 0 :(得分:11)

合成的保留setter看起来像:

- (void)setValue: (id)newValue
{
    if (value != newValue)
    {
        [value release];
        value = newValue;
        [value retain];
    }
}

在您的情况下,您有两种有效的方法:

1)创建一个temp var,alloc / init(=保留),设置为property,release。

IView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
self.overlay = tempOverlay;
[tempOverlay release];

2)没有temp var,直接设置为ivar。

overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

更新: 如果使用方法2),则必须通过释放之前可能存在的任何先前值(如果需要)来显式处理剩余的内存管理(不仅仅是保留)。如果只在init中完成一次(例如),您只需将[overlay release];放入dealloc

答案 1 :(得分:2)

使用retain属性指定应在新对象上调用retain,并将之前的值发送为release

所以在你的第二个代码块中,对象的保留计数将变为2,因为你不再释放它,并且setter保留它。这不太可能是你想要的。

答案 2 :(得分:1)

如果将对象直接分配给属性,则仍必须将其释放:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease];

答案 3 :(得分:1)

由于您的属性定义为(保留)您使用合成setter设置的任何实例(通过self.overlay语法)将自动发送保留消息:

// You're alloc'ing and init'ing an object instance, which returns an 
// instance with a retainCount of 1.
UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

// The overlay property is defined with (retain), so when you assign the new 
// instance to this property, it'll automatically invoke the synthesized setter, 
// which will send it a retain message. Your instance now has a retain count of 2.
self.overlay = tempOverlay;

// Send a release message, dropping the retain count to 1.
[tempOverlay release];

如果你这样做:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

您的叠加层的保留计数为2,这可能会导致应用程序中某个位置出现泄漏。

答案 4 :(得分:0)

感谢您的所有答案。我收到了一些相互矛盾的声明,所以我在UITableViewController中测试了以下内容:

- (id)initWithStyle:(UITableViewStyle)style {
    if ((self = [super initWithStyle:style])) {
        NSLog(@"count: %d", [overlay retainCount]);
        self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
        NSLog(@"count: %d", [overlay retainCount]);
        [overlay release]; NSLog(@"released once");
        NSLog(@"count: %d", [overlay retainCount]);     
        [overlay release]; NSLog(@"released twice");
        NSLog(@"count: %d", [overlay retainCount]);
    }
    return self;
}

我得到了以下控制台输出:

  • 有时它运行良好:

    count: 0
    count: 2
    released once
    count: 1
    released twice
    count: 1
    
  • 其他时候它崩溃了:

    count: 0
    count: 2
    released once
    count: 1
    released twice
    Program received signal:  “EXC_BAD_ACCESS”.
    

我知道使用tempOverlay的方法是正确的。它看起来很麻烦,但我更喜欢它autorelease,因为我不明白autorelease是如何工作的或何时被调用。有一件事是肯定的。上面的代码是错误的,因为我不希望overlay的保留计数为2。

奇怪的是我无法释放它两次。即使它没有崩溃,保留计数也不会减少。

无论如何,我想我现在会坚持使用tempOverlay

答案 5 :(得分:-2)

是的,您可以直接将新创建的对象分配给overlay对象。如果您愿意,您可以通过打印出对象的保留计数来证明自己

NSLog(@"count: %d", [overlay retainCount]);