【问题标题】:How to release IBOutlet defined as property?如何释放定义为属性的 IBOutlet?
【发布时间】:2012-03-06 01:54:24
【问题描述】:

很抱歉这个问题,但我搜索了它并没有找到该案例的答案。

我正在研究 iOS 的内存管理,我理解,或者我认为是,视图生命周期。但现在我有一个关于 IBOutlet 的问题(tat 链接到我的 xib 文件中的 UIImageView)。 我有这样的课:

@interface MyClass : UIViewController 

@property (nonatomic, retain) IBOutlet UIImageView *myImage;

问题是:如何释放 myImage?这样可以吗?

- (void)dealloc {
    self.myImage = nil;
    [super dealloc];
}

- (void)viewDidUnload {
    [super viewDidUnload];
    self.myImage = nil;
}

谁能解释为什么我不能在 myView 上调用 release 方法(如果你有一些喜欢它也很好!)?

提前致谢!

【问题讨论】:

    标签: iphone ios memory-management dealloc


    【解决方案1】:

    您所做的是正确的,您通常不应该在属性上调用 release,因为设置为 nil 已经这样做了,但是如果您的属性有支持 ivar,您可以调用 release...

    【讨论】:

    • 感谢您的回答,您能给我一个指向解释此问题的文档的 URL 吗?因为它似乎是对的,但我不明白为什么:)
    【解决方案2】:

    属性后面有一个属性和一个实例变量。我想它们都被称为 myImage(或者你不会问这个问题)。您可以通过两种方式释放实例 - 释放并 nil ivar,或者 仅 nil 属性。

    保留属性的编译器生成的设置器(如这个)的工作方式如下:释放当前持有的对象引用(如果有),将新值分配给基础 ivar,保留它(如果不是 nil)。所以当你将 nil 赋给一个属性时,它的作用就是释放当前值并用 nil 替换它。

    为此,请使用

    self.myImage = nil; //invoke property setter behind the scenes
    

    要释放 ivar,请使用

    [myImage release];
    myImage = nil;
    

    这在功能上等同于上面的代码。稍微快一点。您应该清楚的是属性和支持 ivars 之间的区别。正是出于这个原因,有些人会为它们分配不同的名称,然后像这样进行合成:

    @synthesize MyImage = _MyImage;
    

    【讨论】:

    • 也许你过度释放了。机会是你的 ivar 点在一个僵尸对象上——一个已经在某个时候被释放的对象。阅读NSZombie 设置,启用它并查看是否是这种情况。
    • 如果这是一个编译错误(而不是运行时错误)-myImage 是什么类型?什么是基类?
    【解决方案3】:

    一般来说,您不会在属性上调用release,而是在相应的 ivar 上调用它。这是我处理IBOutlet 属性的标准方式:

    @interface MyClass
    
    @property (nonatomic, retain) IBOutlet UIImageView *myImageView;
    @property (nonatomic, retain) IBOutlet UILabel *myLabel;
    
    @end
    
    
    @implementation MyClass
    
    @synthesize myImageView = _myImageView;
    @synthesize myLabel = _myLabel;
    
    
    - (void)dealloc {
    
        [_myImageView release];
        [_myLabel release];
    
        [super dealloc];
    }
    
    @end
    

    【讨论】:

    • 如果我尝试使用您的代码,xCode 在“[_myImageView release]”行上给我一个错误...这就是我写问题的原因,我不明白为什么。跨度>
    • 你必须启用 ARC。
    • 不可能,我为iPAD 4.3编译的(在模拟器中)
    • "这个类不符合键 _sectionImageView 的键值编码。"
    • 我不知道为什么,但是今天在我的项目中进行了“清理”之后,您的代码可以完美运行!谢谢!另一个相关的问题:如果我有另一个对象而不是 IBOutlet(如 NSArray),我可以再次使用你的代码吗?这是正确的吗?这种情况下的约定是什么?谢谢:)
    【解决方案4】:

    首先:如果您不支持 4.0 之前的 iOS 版本,请考虑切换到 ARC。

    其次,编写dealloc 方法的最佳实践是不要调用setter。相反,明确释放并取消您的网点:

    [myImage release], myImage = nil;
    

    最后,在将 viewDidUnload 等反初始化方法链接在一起时,请务必在完成自己的工作后调用 super 的实现。

    我们在viewDidUnload 中清除出口的原因是因为有时在系统处于内存压力下时会卸载视图。由于这些 outlet 可以轻松重新创建,因此实现 viewDidUnload 是一种提高性能的方法,并且在极端情况下,可以防止您的应用被强制终止。

    我们在dealloc 中释放属性的原因是为了防止内存泄漏。因此,尽管这两种方法看起来很相似,但它们的用途却有些不同。

    【讨论】:

    • 我知道使用iOS 5的好处,但我必须支持iOS4..问题是[myImage release]这行给我一个错误...
    • 尽管 ARC 是由 iOS 5 附带的 SDK 引入的,但它向后兼容 iOS 4,几乎是透明的。因此,您很有可能在启用 ARC 的情况下创建了项目。如果您在抱怨调用 release 时遇到编译器错误,则几乎可以肯定您做到了。
    • 不用等待,ARC 未激活(我检查过),并且我在代码中调用了数百次 release 方法,它只在这种情况下给我错误。所以我认为这不是与 ARC 相关的错误 :)...
    • 那么公平。您收到的确切错误消息是什么?
    • "这个类不符合键 _sectionImageView 的键值编码。"
    【解决方案5】:

    来自Apple's documentation

    传统模式 在 ARC 之前,管理 nib 对象的规则是 不同于上面描述的那些。您如何管理对象 取决于平台和使用的内存模型。任何 您开发的平台,您应该使用 Objective-C 声明的属性特性。

    声明的一般形式应该是:

    @property (attributes) IBOutlet UserInterfaceElementClass *anOutlet;
    

    由于outlet的行为依赖于平台,实际声明不同:

    对于 iOS,您应该使用:

    @property (nonatomic, retain) IBOutlet UserInterfaceElementClass *anOutlet;
    

    对于 OS X,您应该使用:

    @property (assign) IBOutlet UserInterfaceElementClass *anOutlet;
    

    然后您应该合成相应的访问器方法, 或根据声明实现它们,并且(在 iOS 中)发布 dealloc中对应的变量。

    如果您使用现代运行时并综合,此模式也适用 实例变量,因此它在所有变量中保持一致 情况。

    【讨论】:

    • 这正是我所做的,但是 xcode 在我的 dealloc 中调用 [anOutlet release] 时给了我一个错误...我不明白为什么。
    • Fawk,这真的很奇怪。我有很多这样的代码运行。仔细检查其他可能的问题。祝你好运!
    • 您能否发布您在实施此操作时遇到的错误?
    【解决方案6】:

    我不太明白“为什么我不能在 myView 上调用 release 方法”的意思

    您的代码对我来说似乎是正确的,但按照惯例,我通常更喜欢直接释放 iVar 以获得保留的属性 我通常这样合成我的属性:

    @synthesize myImage = _myImage;
    

    然后你我在dealloc方法中释放iVar

    - (void)dealloc {
         [_myImage release];
         [super dealloc];
    }
    

    Controller 中的任何其他地方我只使用 getter 和 setter(点约定)

    您的 viewDidUnload 是正确的。

    顺便说一句,如果您使用 ARC,只需将您的 IBOutlet 声明为弱指针。它将在内存不足的情况下自动释放,并在您的视图再次加载时重新加载。

    希望这会有所帮助;)

    【讨论】:

    • 谢谢,但这行给了我错误... [_myImage release]。我也认为它是正确的,但它似乎是一个错误。我检查并没有启用 ARC(我在模拟器中使用 iPad 4.3 上的应用程序)
    【解决方案7】:

    IBOutlet 与内存管理无关。

    但是因为是retain属性,所以需要在dealloc中释放。

    所以你的代码是正确的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多