【问题标题】:Weird !=nil check issue奇怪!=无检查问题
【发布时间】:2011-01-07 14:34:55
【问题描述】:

我有一个 UITableViewController,它有一个名为 errorView 的 UIView*,用于在方法无法加载 Web 数据时将错误消息覆盖在表格视图上。

在 init 方法中,errorView 设置为 nil(在调试器中为 0x0)。

在加载方法中,在 init 结束时调用,如果点击了“刷新”UIButton(在 errorView 上),errorView 与 nil 进行比较,如果它不是 nil,则从 superview 中删除并释放(仍然显示 0x0在调试器中)。

在dealloc方法中,释放前做同样的检查;但由于某种原因,即使尚未分配变量(调试器中为 0xc000),该变量也永远不会为零,因为从未调用过数据失败方法。然后应用程序崩溃,因为它试图释放一个空指针,即 != nil。

例子:

-(id)init {
    errorView = nil;
    [self Load];
}

-(void)Load {
    if(errorView != nil) {
        [errorView removeFromSuperView];
        [errorView release];
        errorView = nil;
    }

    //Attempt to load data from web
}

-(void)dataFailedToLoad (e.g. UIWebView didFailLoadWithError) {
    errorView = [[UIView alloc] initWithFrame, etc];
    [self.tableView addSubview:errorView];
}

-(void)dealloc {
    if(errorView != nil)
        [errorView release]; //Always crashes because errorView is never nil even though it has been assigned nil?
}

我正在为此拉头发。除了描述的这些方法之外,errorView 变量在其他任何地方都没有使用,我能读到的所有内容都表明它是正确的方法。

【问题讨论】:

  • 这是实际代码还是最小示例?因为您在 init 和 dealloc 方法中缺少 if((self = [super init])) 和 [super dealloc] 调用...
  • 问题可能不在于errorView 本身。会不会是您发布了两次UITableViewController(或超过您应该发布的次数)?这将导致为无效的UITableViewController 对象调用dealloc 方法,该对象可能在errorView 变量上有垃圾。
  • 这是一个非常精简的版本,是的,原版确实有提到的例程。 UITableViewController 会在视图控制器弹出时自动释放。 (在创建并推入父视图控制器之后)
  • 听起来还是有东西正在写入errorView 变量所在的内存位置。你确定dealloc 只被调用一次吗?如果这不是问题,也许您在errorView 之前的一块内存中存在某种缓冲区溢出,这会覆盖该变量上的值?有时当变量莫名其妙地改变它们的值时,实际上是其他人写出了他们分配的内存位置。
  • 尝试简化问题:当然,此时它可能崩溃的唯一方法是如果 errorView 已被释放但未分配为零? (或从未分配给任何东西)。这两种情况都不是真的。

标签: objective-c uitableview memory-management uiview


【解决方案1】:

作为兴趣点;向 nil 对象发送消息不是错误;您的大量支票完全没用。

如果没有更多信息,很难指出这里到底发生了什么;如果 dataFailedToLoad 实际上 是唯一分配 errorView 的地方,那么您的代码应该可以工作。但是,它的失败表明其他东西正在搞砸你的狗。

顺便说一句,!= nil 的空指针不是空指针。

【讨论】:

  • 我的理解是,安全检查对象是否未分配的唯一方法是在它被释放时分配为零(或者如果它没有立即分配)。并且 errorView 肯定不会在其他任何地方访问。添加errorView功能后出现的问题。
  • 最接近的答案。原来问题是首先调用 [super dealloc] 而不是最后一次调用 -(void) dealloc
  • @Toby Wilson:这就是为什么发布“压缩”代码示例是个坏主意。
【解决方案2】:

仅仅因为您调用了init,视图不必被初始化。您应该使用标准方法viewDidLoad 来确保视图不为零。

【讨论】:

  • 我给出的例子是简化的。实际版本使用 if(self = [super initWithStyle:])
【解决方案3】:

您确定您正在与您认为正在与之交谈的实例交谈吗?

我已经看到了很多 SO 问题,这些问题归结为在加载接口文件 (xib) 实例化的内容与开发人员需要实例化的内容之间存在混淆。

即在所有方法中执行NSLog(@"%@ %p", self, self); 之类的操作,并确保地址(实例)相同。

【讨论】:

    猜你喜欢
    • 2019-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-26
    • 2015-02-27
    • 2018-06-26
    相关资源
    最近更新 更多