我正在调试一个 iOS 应用程序崩溃问题。我有一个UIViewController
我定义它UIView
的地方loadView
。我还保留了 的副本,UIView
以便我可以向它发送消息,例如(视图已旋转)那种性质的东西。除此之外,UIView
它还有自己的委托成员(使用分配,不保留对父级的引用),其中包含与父级的关联。(这是 Apple 文档之一中使用的模式 - 我想知道这是否不是我的问题的一部分,因为两个对象之间存在循环引用)
这是对象的分层视图:
UIViewController
+ UIView
+NSNotificationCenter UIKeyboardDidShow
当NSNotification
forUIKeyboardDidShow
触发并调用父委托方法时会出现此问题。我知道委托已设置。然而,不知何故,代表在某个地方被释放了。此外,仅_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
这就是问题所在。没有更多的崩溃。因此,请确保仅在绝对需要时才注册观察者,并在不需要时取消注册。