【问题标题】:Do I need to release xib resources?我需要释放xib资源吗?
【发布时间】:2010-09-08 21:03:02
【问题描述】:

如果我有类似 UILabel 链接到 xib 文件的东西,我是否需要在视图的 dealloc 上释放它?我问的原因是因为我不分配它,这让我觉得我也不需要释放它? 例如(在标题中):

IBOutlet UILabel *lblExample;

在实施中:

....
[lblExample setText:@"whatever"];
....

-(void)dealloc{
    [lblExample release];//?????????
}

【问题讨论】:

    标签: iphone objective-c cocoa-touch


    【解决方案1】:

    如果您遵循现在被认为是最佳实践的方法,您应该释放 outlet 属性,因为您应该将它们保留在 set 访问器中:

    @interface MyController : MySuperclass {
        Control *uiElement;
    }
    @property (nonatomic, retain) IBOutlet Control *uiElement;
    @end
    
    
    @implementation MyController
    
    @synthesize uiElement;
    
    - (void)dealloc {
        [uiElement release];
        [super dealloc];
    }
    @end
    

    这种方法的优点是它使内存管理语义明确和清晰,并且它在所有平台上对所有 nib 文件一致地工作

    注意:以下 cmets 仅适用于 3.0 之前的 iOS。对于 3.0 及更高版本,您应该简单地将 viewDidUnload 中的属性值设为 nil。

    不过,这里需要考虑的一个问题是,您的控制器可能会处理其用户界面并根据需要动态重新加载它(例如,如果您有一个视图控制器从 nib 文件加载视图,但应请求 - 比如说在内存压力下——释放它,期望在再次需要视图时可以重新加载它)。在这种情况下,您要确保当主视图被处置时,您也放弃任何其他出口的所有权,以便它们也可以被解除分配。对于 UIViewController,您可以通过覆盖 setView: 来处理此问题,如下所示:

    - (void)setView:(UIView *)newView {
        if (newView == nil) {
            self.uiElement = nil;
        }
        [super setView:aView];
    }
    

    不幸的是,这引发了另一个问题。因为 UIViewController 当前使用setView: 访问器方法实现其dealloc 方法(而不是简单地直接释放变量),self.anOutlet = nil 将在dealloc 中被调用以及响应内存警告......这将导致dealloc 崩溃。

    补救措施是确保在dealloc中也将出口变量设置为nil

    - (void)dealloc {
        // release outlets and set variables to nil
        [anOutlet release], anOutlet = nil;
        [super dealloc];
    }
    

    【讨论】:

    • 如果我们有一个 retain 属性,我们不能简单地说 self.uiElement = nil;在我们想要释放的所有地方,因为它是一个保留属性,它实际上应该正确释放它并将其设置为 nil 没有问题,这是保留属性的优点之一。
    • 您通常会在viewDidUnload 中执行self.uiElement = nil; 而不是在setView: 中。在 dealloc 中调用 self.anOutlet = nil; 会更清楚。
    • 你不应该调用 self.anOutlet = nil;在交易中。在 dealloc 中调用访问器是不好的做法。
    • 我完全不同意“在 dealloc 中调用访问器是一种不好的做法”,我经常这样做,这使代码更清晰十亿倍。你有这方面的参考吗?
    • @Wil Shipley:一些 Apple 文档建议不要在 init 和 dealloc 方法中使用访问器。例如:developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/… — AFAICT,基本上除了设置变量之外,setter 可以(并且在 KVO 下)有副作用,如果你触发 KVO 通知,你最终可能会告诉人们在对象被释放后发送消息.
    【解决方案2】:

    我在 Apple 文档中找到了我要查找的内容。简而言之,您可以将对象设置为释放和保留的属性(或者只是 @property、@synthesize),但您不必为 UILabels 之类的东西:

    http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/LoadingResources/CocoaNibs/chapter_3_section_4.html#//apple_ref/doc/uid/10000051i-CH4-SW18

    【讨论】:

      【解决方案3】:

      [anOutlet release], anOutlet = nil;
      

      如果你正确地编写了 setView: 部分是完全多余的。

      【讨论】:

      • 实际上,这在 3.0 及更高版本中有所改变,我了解。我们现在有了 -viewDidUnload,这就是我们释放访问器的地方。
      【解决方案4】:

      如果你不在 dealloc 上释放它,它会增加内存占用。

      See more detail here with instrument ObjectAlloc graph

      【讨论】:

        【解决方案5】:

        【讨论】:

        • @Soeren:我已经阅读了那篇文章,并且了解它的内容。我的问题是关于在 IB xib 上实例化的对象,它没有涵盖。例如:我从来没有真正创建或分配标签,IB 魔法可以做到这一切。所以我需要知道的很简单:我需要释放它吗?
        【解决方案6】:

        在某种意义上,您确实通过在 IB 中创建标签来分配标签。

        IB 所做的是查看您的 IBOutlets 以及它们是如何定义的。如果您有一个类变量,IB 要为某个对象分配引用,IB 会为您向该对象发送一条保留消息。

        如果您使用属性,IB 将使用您必须设置值的属性,而不是显式保留该值。因此,您通常会将 IBOutlet 属性标记为保留:

        @property (nonatomic, retain) UILabel *lblExample;
        

        因此在以太情况下(使用或不使用属性)你应该在你的 dealloc 中调用 release。

        【讨论】:

        • 这是不正确的。如果您不使用属性(或实现自己的访问器方法),那么您是否应该发布取决于您所在的平台以及您的超类是什么。如果你继承自 NSWindowController,例如,你不释放。
        【解决方案7】:

        作为 Nib 主视图的子视图的任何 IBOutlet 都不需要释放,因为它们将在对象创建时发送自动释放消息。您需要在 dealloc 中释放的唯一 IBOutlet 是顶级对象,如控制器或其他 NSObject。这在上面链接的 Apple 文档中都提到了。

        【讨论】:

        • 这实际上是错误的。您是否应该向顶级对象发送发布消息取决于您使用的平台以及文件所有者继承的类。例如,如果它继承自 NSWindowController,则不需要释放它们。
        【解决方案8】:

        如果您不将 IBOutlet 设置为属性,而仅将其设置为实例变量,则仍然必须释放它。这是因为在 initWithNib 时,将为所有 IBOutlets 分配内存。所以这是你必须释放的特殊情况之一,即使你没有在代码中保留或分配任何内存。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-01-05
          • 1970-01-01
          • 2023-01-08
          • 2012-01-22
          • 2013-07-31
          • 1970-01-01
          相关资源
          最近更新 更多