【问题标题】:Why is my property a potential leak and how can I fix it?为什么我的财产可能会泄漏,我该如何解决?
【发布时间】:2011-08-13 05:53:01
【问题描述】:

我的 UIViewController 中有一个 UIScrollView,在我的 .h 文件中定义为:

#import <UIKit/UIKit.h>

@interface TestViewController : UIViewController <UIScrollViewDelegate>

@property (nonatomic, retain) UIScrollView * imageScrollView;

@end

然后在我的 .m 文件中,我有以下内容:

@synthesize imageScrollView = _imageScrollView;

我读到这将自动创建我通常会在 .h 文件中键入的 _imageScrollView? (UIScrollView * _imageScrollView)

我喜欢它,因为它从我的 .h 文件中删除了重复的代码。现在,在我的 loadView 中,我完成了剩下的工作:

self.imageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0 - 20.0 - 49.0)];
[_imageScrollView setDelegate:self];
[_imageScrollView setPagingEnabled:YES];
[_imageScrollView setBounces:NO];
[_imageScrollView setShowsHorizontalScrollIndicator:NO];
[_imageScrollView setShowsVerticalScrollIndicator:NO];
[_imageScrollView setContentSize:CGSizeMake(320.0 * 3.0, 480.0 - 20.0 - 49.0)];

dealloc 版本中和 nil:

- (void)dealloc
{
[_imageScrollView release], _imageScrollView = nil;

[super dealloc];
}

现在构建后 Xcode 告诉我这个:

Potential leak of an object allocated on line #linenumber

当我改变它时它会消失:

self.imageScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0 - 20.0 - 49.0)];

到这里:

self.imageScrollView = [[[UIScrollView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0 - 20.0 - 49.0)] autorelease];

为什么我在 dealloc 中释放它时需要自动释放它?我做错了什么?

此内存警告仅出现在安装了 Lion 的 iMac 上的 Xcode 中,而不出现在安装有雪豹的 Macbook 上...

【问题讨论】:

    标签: objective-c xcode properties release


    【解决方案1】:

    这是因为您的 imageScrollView 属性被声明为 retain 属性。这意味着当您设置它时,访问器(由@synthesize 生成)会自动保留该值。如果您不希望这种行为,您应该将您的属性声明为assign。 (但您确实在这种情况下想要这种行为。)

    无论如何,因此您的对象被保留了两次,一次在您的代码中,一次由访问器保留,因此它永远不会被释放。永远记住 self.imageScrollView = 就像 [self setImageScrollView:] 一样,那里发生的事情!

    (最后,内存警告只发生在 Lion 上,因为旧 Xcode 没有注意到错误,而不是因为错误不存在。)

    【讨论】:

    • 啊,是的,现在对我来说很有意义..(我似乎无法在此处输入)如何避免自动释放?还是在这种情况下它是唯一(也是最好的)选择?通常,当我创建一个临时对象时,我会在完成后立即释放它。当有一种方法可以随时保留它时,用这样的东西填充自动释放池不是很糟糕吗?
    • Autorelease 可能是您最好的选择。确实,自动释放池可能很慢,但前提是所讨论的代码实际上被调用了数千次。如果你在一个紧密的循环中分配了很多东西,那么你可能想要创建一个临时变量来指向你的新视图,将 imageScrollView 设置为它,然后在你的临时变量上调用 release。这样你可以在发布之前设置,所以你不需要自动释放。 (但同样,只有当你注意到它很慢时。)
    • 你的意思是这样的: UIScrollView * imageScrollView = [[UIScrollView alloc] init]; [self setImageScrollView:imageScrollView]; [imageScrollView 发布];该应用程序并不慢(或者至少我没有注意到它),但对于任何未来的项目,我只想弄清楚这一点(但我认为是现在,再次感谢您!)
    • 是的,就像那样(假设您还没有一个名为 imageScrollView 的实例变量,您可能会这样做)。
    • @Rick van der Linde:在这种情况下,自动释放对性能的影响确实可以忽略不计。它本质上是一两个无操作消息发送。
    【解决方案2】:

    您已经使用retain 选项定义了您的属性。这意味着当您将一个对象分配给该属性时,它将被保留——您“获得了该对象的所有权”。在这种情况下,这很好,因为您希望 UIScrollView 在您需要的时候留下来。我应该注意,您还拥有从名称以 allocnewcopymutableCopy 开头的方法返回的任何对象。

    因此,查看您的代码,您可以看到您拥有使用 alloc 创建的 UIScrollView,但是当您将其存储在属性中时,您再次声明了所有权。这意味着内存永远不会被回收。通过调用autorelease,您在将对象分配给属性之前放弃对象的所有权,这意味着在dealloc 中调用release 将按预期工作。

    我建议您阅读 Objective-C 编程语言文档的 Memory Management Programming GuideDeclared Properties 部分。

    【讨论】:

    • 谢谢你的回答 :) 遗憾的是不可能给两个人一个正确的答案!我会再读一遍:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-19
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    相关资源
    最近更新 更多