【问题标题】:Why does iPhone sample code use so many intermediate variables?为什么 iPhone 示例代码使用了这么多中间变量?
【发布时间】:2011-08-12 15:25:35
【问题描述】:

我目前正在研究 Apress 的“开始 iPhone 3 开发”。他们在示例应用程序中使用的标准类似于以下代码:

- (void)viewDidLoad {
    BlueViewController *blueController = [[BlueViewController alloc] 
                                         initWithNibName:@"BlueView" bundle:nil];
    self.blueViewController = blueController;
    [self.view insertSubview:blueController.view atIndex:0];
    [blueController release];
}

8.14.11 更新(附加信息)
blueViewController 声明如下:

@property (retain, nonatomic) BlueViewController *blueViewController;

每当他们执行alloc 时,他们会将其放入某个临时变量(此处为blueController),然后分配它,然后释放它。这个临时变量对我来说似乎是多余的。
我将代码简化如下:

- (void)viewDidLoad {
    self.blueViewController = [[BlueViewController alloc] 
                              initWithNibName:@"BlueView" bundle:nil];
    [self.view insertSubview:blueViewController.view atIndex:0];
}

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

我修改后的代码在 iPhone 模拟器中运行相同。 现在,我知道了如果你分配了一些东西就需要释放它的规则。我在我的dealloc 方法中介绍了这一点。但是直接在ViewDidLoad(调用alloc 的函数)中发布有什么好处吗?或者像这样在您的 dealloc 方法中使用 release 是否同样可以?
感谢您的帮助,
-j

【问题讨论】:

    标签: objective-c ios memory-management simplification


    【解决方案1】:

    假设blueViewControllerretain 属性,则临时变量并非多余。您的简化正在造成内存泄漏。来自第二个 sn-p 的这句话泄露了:

    self.blueViewController = [[BlueViewController alloc] 
                              initWithNibName:@"BlueView" bundle:nil];
    

    在所有权方面,您拥有 alloc-init 返回的对象,然后属性访问器再次声明该对象的所有权,导致该对象过度保留

    使用临时变量可以解决这个问题。另一种选择是使用autorelease

    self.blueViewController = [[[BlueViewController alloc] 
                              initWithNibName:@"BlueView" bundle:nil] autorelease];
    

    请注意,在此声明之后,您实际上拥有该对象,并且您必须在 dealloc 中释放它。


    您没有提到属性blueViewController 是如何声明的。无论如何,无论 setter 的语义是什么(retaincopyassign),这种说法都是错误的。我已经解释了最可能的情况:retain。让我们看看其他两种可能性(不考虑它们是否有意义):

    • 如果 blueViewController 恰好是 copy 属性,则该语句也会泄漏。属性访问器复制了原始对象,现在该属性保存了一个指向副本的指针,而您丢失了原始对象的踪迹,立即泄漏了它。

    • 最不可能的情况是blueViewControllerassign 属性,因为这很可能是错误的,而您确实需要retain。但是,无论如何,assign 属性适用于您不拥有的对象,例如代表,你不应该释放他们。您正在将一个您拥有的对象分配给它,因此您要么泄漏它,要么错误地释放了 assign 属性。

    【讨论】:

    • 这是一个很好的观点,而且我的回答不仅仅指风格点。通常,如果您希望直接将新对象分配给 ivar,则应使用自动释放的便捷方法。如果必须使用名称中包含 alloc、init、new 或 copy 的方法,则必须将其分配给 temp 然后释放它。
    • 谢谢 albertamg,这回答了我的问题。感谢您抽出宝贵时间做出解释。
    • 我在想release 可以覆盖无限数量的allocs 和retains。我认为这是重要的区别,release 所做的只是将对象的保留计数减 1。
    【解决方案2】:
    @property (retain) MyCLass *obj;
    
    MyClass *tmpObj = [[MyClass alloc] init];
    self.obj = tmpObj;
    [tmpObj release];
    

    在第一行中,您可以通过alloc 获得一次所有权。然后在第二行,您再次获得所有权,因为该财产被保留。在第 3 行中,您释放通过 alloc 获得的所有权。现在您通过保留属性拥有单一所有权,您将来可能会释放它,可能位于dealloc

    现在考虑如果删除 tmpObj 会发生什么。

    self.obj = [[MyClass alloc] init];
    

    在这一行中,您获得两次所有权,一次通过alloc,一次通过财产。现在[obj release] 一次是不够的。您需要释放它两次以避免泄漏,自然释放两次是非常糟糕的,并且可能是进一步内存泄漏的来源。如果您再次致电self.obj = anotherObj,那么您正在泄漏旧电话。为避免这种情况,您需要此临时指针。

    【讨论】:

    • Taskinoor- 感谢您的回答。这绝对有助于我更好地理解 Objective c 的内存管理。
    【解决方案3】:

    我能想到的原因有两个;第一个,更具体的示例是,您经常会看到类似的方法,其中 blueController 被分配和初始化,然后在实际分配给 self 的 ivar 之前测试有效性。在每个此类方法中遵循此模式将使您更容易在创建对象和分配对象之间进行测试,如果您意识到需要发生这种情况。据我所知,如果这样的中介确实是多余的,编译器应该优化它。

    在 Cocoa 中这种模式的第二个更通用的目的是 Obj-C 和 Cocoa 鼓励方法和变量使用极长、冗长的名称,因此单个方法调用最终可能跨越多行;使用方法调用作为其他方法的直接参数很快就会变得不可读,因此约定鼓励提前为方法设置每个参数,将它们放在中间变量中,然后将变量用作参数以增强可读性,并使其更容易更改单个参数,而无需挖掘嵌套的方法调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-19
      • 2021-03-29
      • 1970-01-01
      • 2014-04-17
      相关资源
      最近更新 更多