我的应用支持来自多个云服务(Dropbox,Google Drive等)的授权,并使用适当的SDK。每个SDK都通过呈现Web视图来提供授权,用户可以在其中输入其凭据。问题是,在以下情况下,Web视图会使应用程序崩溃:
以下信息将打印到控制台中。
2017-03-22 19:17:55.564 MyApplicationName[46315:16017957] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
*** First throw call stack:
(
0 CoreFoundation 0x000000010e63ff65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x0000000111960deb objc_exception_throw + 48
2 CoreFoundation 0x000000010e506f55 -[__NSArrayM insertObject:atIndex:] + 901
3 UIKit 0x000000011206fcd4 -[UIViewController _addChildViewController:performHierarchyCheck:notifyWillMove:] + 541
4 UIKit 0x00000001127e9581 -[UIInputWindowController changeToInputViewSet:] + 1420
5 UIKit 0x00000001127e218f -[UIInputWindowController moveFromPlacement:toPlacement:starting:completion:] + 369
6 UIKit 0x00000001127ea01b -[UIInputWindowController setInputViewSet:] + 983
7 UIKit 0x00000001127e1e17 -[UIInputWindowController performOperations:withAnimationStyle:] + 50
8 UIKit 0x00000001124fb397 -[UIPeripheralHost(UIKitInternal) setInputViews:animationStyle:] + 1275
9 UIKit 0x00000001120e0c89 -[UIResponder(UIResponderInputViewAdditions) reloadInputViews] + 81
10 UIKit 0x0000000112527604 -[UIWebBrowserView _reloadInputViewsAfterPotentialFocusRedirect] + 54
11 UIKit 0x00000001125274a9 -[UIWebBrowserView _endAllowingFocusRedirects] + 45
12 libdispatch.dylib 0x00000001149d149b _dispatch_client_callout + 8
13 libdispatch.dylib 0x00000001149bacd8 _dispatch_barrier_sync_f_slow_invoke + 284
14 libdispatch.dylib 0x00000001149d149b _dispatch_client_callout + 8
15 libdispatch.dylib 0x00000001149b934b _dispatch_main_queue_callback_4CF + 1738
16 CoreFoundation 0x000000010e5a03e9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
17 CoreFoundation 0x000000010e561939 __CFRunLoopRun + 2073
18 CoreFoundation 0x000000010e560e98 CFRunLoopRunSpecific + 488
19 GraphicsServices 0x0000000115eafad2 GSEventRunModal + 161
20 UIKit 0x0000000111ee0676 UIApplicationMain + 171
21 MyApplicationName 0x000000010c161682 main + 114
22 libdyld.dylib 0x0000000114a0592d start + 1
23 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
显然,在点击文本字段时会出现此问题,因此我决定通过打开google.com并点击其中的文本字段来测试它,以确保应用程序崩溃。 该应用程序没有崩溃,但在我显示/隐藏键盘时它确实打印了以下信息。
2017-03-22 20:31:52.453 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidFocusNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2017-03-22 20:31:54.985 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidBlurNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2017-03-22 20:31:56.341 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidFocusNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2017-03-22 20:31:58.029 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidBlurNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2017-03-22 20:32:00.675 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidFocusNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
2017-03-22 20:32:02.872 MyApplicationName[55324:16092779] *** WebKit discarded an uncaught exception in the webView:elementDidBlurNode: delegate: <NSInvalidArgumentException> *** -[__NSArrayM insertObject:atIndex:]: object cannot be nil
我怀疑键盘的工具栏存在一些问题,因为如果你看一下this gif,你会发现工具栏第一次出现,但第二次没有出现,出现了QuickType一会儿。
其他信息: - 我无法在示例项目中重现该问题,即当我试图在google.com上崩溃应用程序时,日志中没有崩溃或错误。 - 我不太可能在UIWindow上有一些手势识别器,在那里检查。
所以问题是:我该如何解决这个问题?
答案 0 :(得分:1)
在UIInputWindowController的changeToInputViewSet中,您尝试添加子视图控制器,但该子视图控制器为nil。找出你的视图控制器为零的原因,然后解决这个问题。你有一个可重复的序列来揭示崩溃。在changeToInputViewSet的开头放置一个断点,并逐步查看您正在使用的任何viewControllers的值。这是你的错误。
答案 1 :(得分:0)
好的,所以我设法找出导致这种行为的原因。下面的这个小扩展导致了这个错误。
extension UIViewController {
/**
Simple shortcut for trivial cases.
Adds a child controller to the view, that is a descendant of `self.view`.
By default, child controller's view is stretched in the passed view.
Use `constraintsSetupBlock` to setup constraints as you need.
*/
func addChildViewController(childController: UIViewController, to view: UIView, constraintsSetupBlock: ((view: UIView, childControllerView: UIView) -> Void)? = nil) {
guard view.isDescendantOfView(self.view) else {
fatalError("`view` must be a descendand of `self.view`")
}
addChildViewController(childController)
view.addSubview(childController.view)
if let setupBlock = constraintsSetupBlock {
setupBlock(view: view, childControllerView: childController.view)
} else {
childController.view.snp_makeConstraints(closure: { (make) in
make.edges.equalTo(view)
})
}
childController.didMoveToParentViewController(self)
}
/**
Simple shortcut for trivial cases.
`childController` is optional purely for convenience.
*/
func removeChildViewController(childController: UIViewController?) {
guard let controller = childController else { return }
controller.willMoveToParentViewController(nil)
controller.view.removeFromSuperview()
controller.didMoveToParentViewController(nil)
}
}
我的猜测是这些方法的名称与某些SDK的私有方法相匹配,并且在运行时系统选择了我的实现,这导致了非常不愉快的结果。