在iOS上,在UIView的实例方法中,如果我们[self removeFromSuperview],为什么自我继续存在?

时间:2012-09-27 19:01:44

标签: objective-c ios

如果我们将UIView子类化,并且在任何新类的实例方法中,请执行

[self removeFromSuperview];

[foo someMessage];
_a = _a + 1;
self.b++;
for (int i = 0; i < 100000000; i++) {
    self.b++;
    //NSLog(@"b is %i", self.b);
}

会发生什么?假设超级视图是唯一一个声称拥有此视图的人,那么self会立即被释放吗?

第一行是发送一个引用外部对象的本地变量foo消息someMessage。第二行是局部变量_b。第三行是属性b。接下来的几行只是做了一些延迟。

尝试使用Xcode 4.5和iPhone 5(iOS 6),代码实际运行时不会崩溃。代码在-touchesBegan内完成。只有在大延迟循环结束后,视图才会在屏幕上消失,这可能是由于主循环现在为drawRect调用rootViewController.view并显示视图已消失(视图已从视图层次结构中消失)在延迟循环之前,但尚未在屏幕上反映出来。)

如果我使循环只计数到1000或10000,并在该循环内使用NSLog,那么该数字实际打印得很好而没有任何崩溃。 更新:据说该对象可能仍然可以访问一段时间,但似乎即使是30秒或一分钟,代码仍然运行没有任何问题。

那么这是如何工作的?如果使用Instruments,我实际上看到这个FooView对象仅在大延迟循环之后才离开“分配”表。所以奇怪的是,似乎FooView对象直到后来都没有被释放,而不是removeFromSuperView

我还有一个[self.presentingViewController dismissViewControllerAnimated ...]被解雇self,然后下一行self.presentingViewController再次被使用,self.presentingViewController变为nil,但如果我还添加一个循环来增加10000的整数属性并使用NSLog将其打印出来,它也很好地打印出来。

1 个答案:

答案 0 :(得分:1)

  

假设超级视图是唯一一个声称拥有此视图的人,那么会立即自行解除分配吗?

是的,可能,但内存实际上并没有被重用或清除;如果在重新分配后没有其他任何事情发生,经常仍然可以获得看似有效的对象。

尝试:

[self removeFromSuperview];
[self performSelector:@selector(tryToCrash) withObject:nil afterDelay:0.1];

//...

- (void)tryToCrash
{
    [foo someMessage];
    _a = _a + 1;
    self.b++;
    for (int i = 0; i < 100000000; i++) {
        self.b++;
        //NSLog(@"i is %i", self.i);
    }
}

将调度该代码在下一次运行循环后发生,并且您可能会看到崩溃。最重要的是你正在使用一个你知道死的物体,这个物体并不完全达到C的UB水平,但肯定不能保证给你任何特定的结果。

  

只有在大延迟循环结束后,视图才会在屏幕上消失,这可能是由于主循环现在调用drawRect

是的,只有在每次通过运行循环时才会重新绘制视图,并且只有在它们被标记为需要它时才会重新绘制。由于其中一个子视图已被删除,因此superview将如此标记。它也可能推迟实际释放子视图直到这一点。