【问题标题】:Changes to reference counting in iOS 7?iOS 7 中引用计数的变化?
【发布时间】:2013-09-26 10:46:09
【问题描述】:

我目前正在修复一个不是使用 ARC 构建的旧版应用程序上的一些 iOS 7 显示问题,并且在 iOS 版本 6 和 7 之间遇到了与 dealloc 方法不一致的行为。我不能在任何文档或社区讨论中找到有关这些更改的任何其他提及,所以我想知道这里是否有人可以阐明这里发生的事情?

我之前的代码,(在 iOS6 中工作,看起来像这样):

@interface MyViewController()
@property (retain) AdHandler *adHandler;
@end

@implementation MyViewController

@synthesize adHandler = _adHandler;

- (id) initWithAdHandler:(AdHandler*)anAdHandler
{
    self = [super init];
    _adHandler = [anAdHandler retain];
    return self;
}

- (void)dealloc
{    
    [super dealloc];

    [_adHandler release];
    _adHandler = nil;
}

...

@end

在iOS 6中单步执行代码时,我发现dealloc语句之后,[_adHandler retainCount]仍然是正数,并且对象仍然可用。

然而,在 iOS 7 中,dealloc 语句之后,retainCount 以某种方式达到零,并且_adHandler 对象一直是dealloc'd,因此我对release 的调用会导致EXC_BAD_ACCESS .

我可以通过将我的 [adHandler release] 呼叫移动到 dealloc 呼叫之前来解决此问题,但我的问题是为什么会发生这种情况?为什么dealloc 释放它不负责的对象?是否有任何文档说明为什么 dealloc 行为会以这种方式发生变化?

【问题讨论】:

  • 在非 ARC 应用程序中实现 -dealloc 时,[super dealloc] 应该是最后一个语句,而不是第一个。
  • 如果您使用工具,您可以准确了解对象上发生保留/释放/自动释放的位置
  • 你的init方法也不正确。
  • @majackson 你需要做self = [super init]; if (self) { ... initialization junk } return self; 标准模式。而且,正如其他人所说,retainCount 完全没用,即使用于调试也是如此。

标签: ios objective-c xcode ios7 reference-counting


【解决方案1】:

[super dealloc] 之后的实例是垃圾,无论发生什么都是相当随机和不确定的。正如@bneely 所写,[super dealloc] 必须排在最后。

最佳实践:转换为 ARC。

至于retainCount,无法保证它的值是多少,不要使用它,它只会造成混乱。在您的情况下,您通过调用 [super dealloc] 销毁了类实例,然后期望该实例的行为就像它仍然存在一样。它不能,它已经被销毁了,现在只是内存中的一些不确定的位。

【讨论】:

  • 但是在dealloc之后,_adHandler仍然包含一个内存地址,并且该内存地址中的对象不应该有release调用它,所以应该仍然存在?
  • @majackson 内存可能已经被覆盖,尤其是在Debug模式下
  • @Sulthan 如果retainCount 没有达到零,为什么内存会被覆盖?其他对象可能有对该对象的引用!还是您的意思是包含对象地址的内存?
  • @majackson 当super dealloc 被调用时,内存返回给系统。它可以立即被覆盖。如果你稍后调用self.something,你得到的指针是完全随机的(未定义)。 retainCount 的值完全不相关,因为如果不实际查看 Apple 的源代码,您将无法理解它。
  • @majackson 我很确定代码会在 Xcode 4 中触发警告。请注意,在调试模式下,可以立即覆盖内存,以便在再次访问时触发异常。在[super dealloc] 之后有代码总是错误和危险的。
【解决方案2】:

You should never use retain count.

您无法以任何合理的方式解释它返回的值。因此,完全可以预期在不同的 iOS 版本、设备、不同的代码位数等上看到不同的结果。


顺便说一句,您是否考虑改用 ARC?代码将大大简化。另请注意,如果您正在实现UIViewController 的子类,则不应使用init 对其进行初始化。只需声明属性,ARC 就会处理它的 setter 和 getter:

@interface MyViewController : UIViewController
@property AdHandler *adHandler;
@end

// somewhere else 
MyViewController * mvc = ... from nib or in some other way ...
mvc.adHandler = myAdHandler;

现在保证您没有错误的访问。

【讨论】:

  • 我使用retainCount 仅用于调试目的,不在生产代码中。
  • retainCouut 正在引起混乱!不要使用它。
  • 至于 ARC,我非常喜欢使用它进行 iOS 开发,当然也打算在某个时候迁移,但目前没有足够的时间将这个(相当大的)应用程序迁移到 ARC。
  • 这实际上并不能回答问题。
  • 我同意,我有点侧身。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-03
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 2014-06-23
相关资源
最近更新 更多