IPhone 4 Plus error UISplitViewController with recursive _canBecomeDeepestUnambiguousResponder

I have an existing iPhone app that I am adding UISplitViewController to. Part of the iPad works like a charm, but I have a guaranteed crash with the iPhone 6 (S) Plus.

Settings - Wizard - UITabBarController . The initial detail is a view with the appearance of a placeholder logo. After selecting an object, the part is replaced by a UITabBarController .

Whenever I select an item and open Detail in iPhone 6 Plus and rotate it from the portrait (only the visible part) into the landscape (where the wizard will be visible), it will work. This does not happen when rotating with a detailed representation of the placeholder.

Before the failure, it calls the delegate methods primaryViewControllerForExpandingSplitViewController and splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController . However, everything works well on the iPad.

I have searched many times and seen only a couple of tweets mentioning this type of accident. Things like installing or not installing displayModeButtonItem don't help.

I recreated this collapse in a new project - it can be downloaded here: https://github.com/sschale/SplitViewCrash/

Failure Log:

 Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_BAD_ACCESS (SIGSEGV) Exception Codes: KERN_PROTECTION_FAILURE at 0x00007fff53609ff8 Exception Note: EXC_CORPSE_NOTIFY VM Regions Near 0x7fff53609ff8: MALLOC_TINY 00007f8405000000-00007f8405300000 [ 3072K] rw-/rwx SM=PRV --> STACK GUARD 00007fff4fe0a000-00007fff5360a000 [ 56.0M] ---/rwx SM=NUL stack guard for thread 0 Stack 00007fff5360a000-00007fff53dff000 [ 8148K] rw-/rwx SM=COW thread 0 Thread 0 Crashed:: Dispatch queue: com.apple.main-thread 0 liboainject.dylib 0x000000010e5e59b2 0 liboainject.dylib 0x000000010e5e59b2 _writeEventToSharedMemory + 27 1 liboainject.dylib 0x000000010e5e55d7 _OARecordFinalEvent + 1161 2 liboainject.dylib 0x000000010e5e79f1 ___swapMethods_block_invoke_6 + 338 3 libobjc.A.dylib 0x000000010f4f9b6b weak_read_no_lock + 89 4 libobjc.A.dylib 0x000000010f4fa4c6 objc_loadWeakRetained + 104 5 com.apple.UIKit 0x00000001110510b6 -[UIViewController presentedViewController] + 58 6 com.apple.UIKit 0x0000000111033fc6 -[UIViewController _canBecomeDeepestUnambiguousResponder] + 31 7 com.apple.UIKit 0x0000000111033fde -[UIViewController _canBecomeDeepestUnambiguousResponder] + 55 8 com.apple.UIKit 0x0000000111033fde -[UIViewController _canBecomeDeepestUnambiguousResponder] + 55 9 com.apple.UIKit 0x0000000111033fde -[UIViewController _canBecomeDeepestUnambiguousResponder] + 55 10 com.apple.UIKit 0x0000000111033fde -[UIViewController _canBecomeDeepestUnambiguousResponder] + 55 //(500 more of those) .... Thread 1:: Dispatch queue: com.apple.libdispatch-manager 0 libsystem_kernel.dylib 0x0000000116e49ee2 kevent64 + 10 1 libdispatch.dylib 0x0000000116ac57f0 _dispatch_mgr_invoke + 260 2 libdispatch.dylib 0x0000000116ac558a _dispatch_mgr_thread + 54 Thread 2: 0 libsystem_kernel.dylib 0x0000000116e495e2 __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x0000000116e0d578 _pthread_wqthread + 1283 2 libsystem_pthread.dylib 0x0000000116e0b341 start_wqthread + 13 Thread 3: 0 libsystem_kernel.dylib 0x0000000116e495e2 __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x0000000116e0d578 _pthread_wqthread + 1283 2 libsystem_pthread.dylib 0x0000000116e0b341 start_wqthread + 13 Thread 4: 0 libsystem_kernel.dylib 0x0000000116e495e2 __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x0000000116e0d578 _pthread_wqthread + 1283 2 libsystem_pthread.dylib 0x0000000116e0b341 start_wqthread + 13 Thread 5: 0 libsystem_kernel.dylib 0x0000000116e495e2 __workq_kernreturn + 10 1 libsystem_pthread.dylib 0x0000000116e0d578 _pthread_wqthread + 1283 2 libsystem_pthread.dylib 0x0000000116e0b341 start_wqthread + 13 
+7
ios swift iphone-6-plus uisplitviewcontroller
source share
1 answer

It also knocks down the iPad. Use Multitasking to resize the application to a compact width (for example, 1/3 of the screen), click the "Launch Detail" button, and then change it to its normal width.

When you are in compact width, the split view controller will crash. This means that it no longer displays the individual primary and secondary view controllers at the same time; instead, it "collapses" them into a single view controller hierarchy. When this happens in this environment, you often need your help to act wisely. The default behavior works well when your primary and secondary view controllers are UINavigationControllers, but not in other cases.

(In your application, your main element is the UITabBarController, and after you “Run the part” once, the secondary is also the UITabBarController. You may want to review this design because it complicates the work. Keep reading.)

Your Launch Detail application executes a Show Detail segue, which effectively calls this method in the UISplitViewController:

 public func showDetailViewController(vc: UIViewController, sender: AnyObject?) 

Note the comment in the title:

 // In a horizontally-compact environment the master view controller // or detail view controller is sent the showViewController:sender: // message. If neither one of them provide an implementation for this // method then it will fall back to a full screen presentation. 

Under “master view controller or detail view controller”, this means that the view manager, which in your case is a UITabBarController, is currently displayed. But the UITabBarController does not implement anything for showViewController() , because it does not have enough information - where would it display the view controller? Will she add a new tab or replace the old one or what?

So, as a result, you get this backup, full-screen presentation. I doubt that you really need this user.

Later, when the size changes to Normal, and the split view controller expands, it gets confused in the presentation and eventually works. (See what I mean that the defaults are not very good?)

One way to fix this is to implement the delegate method to handle showDetail . When the width is Compact, explicitly find the view controller on which you want to place the new view controller, and do it. I think you probably want to click on the navigation controller in the first tab:

 func splitViewController(splitViewController: UISplitViewController, showDetailViewController vc: UIViewController, sender: AnyObject?) -> Bool { if splitViewController.traitCollection.horizontalSizeClass == .Compact { // The default implementation will not handle this properly. // Find the appropriate navigation controller and push onto it. // It would be better to have a direct outlet to the appropriate navigation controller, // but this will work for an example... if let tabBarController = splitViewController.viewControllers.first as? UITabBarController { if let navController = tabBarController.viewControllers?.first as? UINavigationController { navController.pushViewController(vc, animated: true) // we handled the "show detail", so split view controller, // please don't do anything else return true } } } // we did not handle the "show detail", so split view controller, // please do your default behavior return false } 

If you do this, you will also want to implement this delegate method. When the size is changed to "Normal", you will want to handle the "expand" by pulling this view controller from the same navigation controller, and then return it:

 optional public func splitViewController( splitViewController: UISplitViewController separateSecondaryViewControllerFromPrimaryViewController primaryViewController: UIViewController) -> UIViewController? 
+4
source share

All Articles