随机释放UIViewController

时间:2012-05-16 23:57:03

标签: objective-c uiview uiviewcontroller

我正忙着调试iOS应用崩溃问题。我有一个UIViewController,我在UIView中定义了loadView。我还保留了UIView的副本,以便我可以向其发送消息,例如(视图已经旋转)这种性质的东西。除此之外,UIView还有自己的委托成员(使用assign,不保留引用父对象),其中包含与父对象的关联。 (这是其中一个Apple文档中使用的模式 - 我想知道这不是我的问题的一部分,因为这两个对象之间存在循环引用)

以下是对象的分层视图:

UIViewController + UIView   + NSNotificationCenter UIKeyboardDidShow

NSNotification触发UIKeyboardDidShow并调用父委托方法时,会出现此问题。我知道代表是 set 。然而,某种程度上,代表正在被释放。此外,_bufferViewDelegate仅设置 一次。最后,每次都不会发生这种情况。它很少发生。

这是堆栈跟踪:

Exception Type:  EXC_CRASH (SIGABRT)
Exception Codes: 0x00000000, 0x00000000
Crashed Thread:  0

Last Exception Backtrace:
0   CoreFoundation                  0x325f288f __exceptionPreprocess + 163
1   libobjc.A.dylib                 0x34648259 objc_exception_throw + 33
2   CoreFoundation                  0x325f5a9b -[NSObject doesNotRecognizeSelector:] + 175
3   CoreFoundation                  0x325f4915 ___forwarding___ + 301
4   CoreFoundation                  0x3254f650 _CF_forwarding_prep_0 + 48
5   Buffer                          0x0008716d -[BufferView scrollToCursor] (BufferView.m:4348)
6   Buffer                          0x00080407 -[BufferView keyboardDidShow:] (BufferView.m:1379)
7   Foundation                      0x37f3d4ff __57-[NSNotificationCenter addObserver:selector:name:object:]_block_invoke_0 + 19
8   CoreFoundation                  0x325be547 ___CFXNotificationPost_block_invoke_0 + 71
9   CoreFoundation                  0x3254a097 _CFXNotificationPost + 1407
10  Foundation                      0x37eb13eb -[NSNotificationCenter postNotificationName:object:userInfo:] + 67
11  UIKit                           0x3209f029 -[UIInputViewTransition postNotificationsForTransitionEnd] + 789
12  UIKit                           0x3233a51f __53-[UIPeripheralHost(UIKitInternal) executeTransition:]_block_invoke_01008 + 159
13  UIKit                           0x320344db -[UIViewAnimationBlockDelegate _didEndBlockAnimation:finished:context:] + 215
14  UIKit                           0x3202eaab -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 471
15  UIKit                           0x320343d5 -[UIViewAnimationState animationDidStop:finished:] + 53
16  QuartzCore                      0x342dbc2f CA::Layer::run_animation_callbacks(void*) + 203
17  libdispatch.dylib               0x35c4ae91 _dispatch_main_queue_callback_4CF$VARIANT$up + 197
18  CoreFoundation                  0x325c52ad __CFRunLoopRun + 1269
19  CoreFoundation                  0x325484a5 CFRunLoopRunSpecific + 301
20  CoreFoundation                  0x3254836d CFRunLoopRunInMode + 105
21  GraphicsServices                0x3169f439 GSEventRunModal + 137
22  UIKit                           0x32047cd5 UIApplicationMain + 1081
23  Buffer                          0x0005c20b main (main.m:20)
24  Buffer                          0x0005bcac start + 40

更新2:

解决了这个问题。我所做的是将NSLog语句放在控制器和所有子视图中,以确定是否所有内容都按照我的预期发布。事实并非如此。我所期待的,并且在大多数时间里发生的是:

UIViewController loadView <-- Open the view, init the BufferView
UIViewController dealloc
BufferView dealloc

发生的事情是,有时BufferView的dealloc方法从未被称为!

UIViewController中的代码如下所示:

- (void)loadView
{
    ...

    // bufferView is a member var of this particular UIViewController
    bufferView = [[BufferView alloc] init];
    [self addSubview:view];

    ...
}

当调用UIViewController dealloc方法时,我会释放bufferView。

- (void)dealloc
{
    ...

    [bufferView release];
    bufferView = nil;

    ...

    [super dealloc];
}

当我在loadView中将代码更改为:

- (void)loadView
{
    ...

    // bufferView is a member var of this particular UIViewController
    bufferView = [[BufferView alloc] init];
    [self addSubview:view];
    [bufferView release];

    ...
}

并删除了dealloc中的release命令,一切都按预期开始工作。似乎最佳做法是在将视图添加到子视图后释放视图。我在其他应用程序中看到过这种模式,但从未理解为什么必须采用这种方式。希望这有助于其他人。

请注意,我在一天内没有遇到过崩溃。这比以前好多了。如果这是错误的解决方案,我会更新票证。

更新3

以上不起作用。我现在在UIViewController viewWillAppear,viewDidDisappear方法中注册/取消注册通知。问题解决了。据我所知,每个人的建议是将[[NSNotification defaultCenter] removeObserver:self]调用放在dealloc中。这根本不是一个好主意。您不能依赖系统在您期望它发生的时间范围内释放您的对象。也许在某些情况下它可以正常工作,但不是全部。我建议您只在需要时尝试注册/取消注册。在我的情况下,我只在显示视图时需要它们,在未显示视图时取消注册。一天免费崩溃(我们会看到持续多久)。我会在几天内更新我的成功。

更新4

这就是问题所在。没有更多的崩溃。因此,请确保仅在您绝对需要时注册观察者,并在不需要时注销观察者。

1 个答案:

答案 0 :(得分:1)

要找出对象被解除分配的时间,请在其dealloc例程中放置一个NSLog。在dealloc中放置一个地址停止将允许您显示调用堆栈,并查看谁正在执行释放该对象的release

我怀疑你所拥有的是该对象实际上比你想象的更快被解除分配,但是在定时器事件期间,存储被回收,并且就是在检测到错误时。