5

我在标题中有以下内容:

@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)];
4

6 回答 6

11

合成的保留设置器如下所示:

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

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

1)创建一个临时变量,alloc/init(=保留),设置为属性,释放。

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

2)没有临时变量,直接设置为ivar。

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

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

于 2010-10-13T15:16:31.210 回答
2

使用该retain属性指定retain应该在新对象上调用,并且先前的值被发送一个release.

因此,在您的第二个代码块中,对象的保留计数将变为 2,因为您不再释放它,而 setter 正在保留它。这不太可能是您想要的。

于 2010-10-13T14:04:15.127 回答
1

如果您将对象直接分配给属性,您仍然必须释放它:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease];
于 2010-10-13T14:20:44.583 回答
1

由于您的属性是使用(保留)定义的,因此您使用合成设置器(通过 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,这可能会导致应用程序中的某个点发生泄漏。

于 2010-10-13T15:07:48.207 回答
0

谢谢你的所有答案。我得到了一些相互矛盾的说法,所以我在 a 中测试了以下内容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

于 2010-10-14T00:27:01.827 回答
-2

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

NSLog(@"count: %d", [overlay retainCount]);
于 2010-10-13T14:10:32.967 回答