我正忙着调试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
这就是问题所在。没有更多的崩溃。因此,请确保仅在您绝对需要时注册观察者,并在不需要时注销观察者。
答案 0 :(得分:1)
要找出对象被解除分配的时间,请在其dealloc
例程中放置一个NSLog。在dealloc
中放置一个地址停止将允许您显示调用堆栈,并查看谁正在执行释放该对象的release
。
我怀疑你所拥有的是该对象实际上比你想象的更快被解除分配,但是在定时器事件期间,存储被回收,并且就是在检测到错误时。