1

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

这是对象的分层视图:

UIViewController + UIView +NSNotificationCenter UIKeyboardDidShow

NSNotificationforUIKeyboardDidShow触发并调用父委托方法时会出现此问题。我知道委托已设置。然而,不知何故,代表在某个地方被释放了。此外,_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

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

4

1 回答 1

1

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

我怀疑你所拥有的是对象实际上比你想象的更快地被释放,但是在计时器事件期间,存储被回收,那就是检测到错误的时候。

于 2012-05-17T01:46:07.550 回答