ios - iPhone 6 Plus UISplitViewController crash with recursive _canBecomeDeepestUnambiguousResponder -
i have existing iphone app i'm adding uisplitviewcontroller
to. ipad part works charm, i'm having guaranteed crash iphone 6(s) plus.
setup - master uitabbarcontroller
. initial detail view placeholder logo view. once object selected, detail replaced uitabbarcontroller
.
whenever select item , open detail in iphone 6 plus , rotate portrait (detail visible) landscape (where master visible), crashes. not occur on rotation placeholder detail view.
before crash, call delegate methods primaryviewcontrollerforexpandingsplitviewcontroller
, splitviewcontroller(splitviewcontroller: uisplitviewcontroller, separatesecondaryviewcontrollerfromprimaryviewcontroller
. however, works fine on ipad.
i've done ton of searching , seen couple twitter mentions of type of crash. things setting or not setting displaymodebuttonitem
don't help.
i recreated crash in fresh project - can downloaded here: https://github.com/sschale/splitviewcrash/
crash log:
crashed thread: 0 dispatch queue: com.apple.main-thread exception type: exc_bad_access (sigsegv) exception codes: kern_protection_failure @ 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 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
this crashes on ipad too. use multitasking resize app compact width (e.g. 1/3rd screen), press launch detail button, resize regular width.
when you're in compact width, split view controller "collapsed". means no longer shows separate primary , secondary view controllers @ same time -- instead, "collapses" them single view controller hierarchy. when it's in environment, needs in order act sensibly. default behavior works when both primary , secondary view controllers uinavigationcontrollers, not in other cases.
(in app, primary uitabbarcontroller, , after "launch detail" once, secondary uitabbarcontroller. may want reconsider design, because makes things more difficult. keep reading.)
your app's "launch detail" button performs "show detail" segue, calls method on uisplitviewcontroller:
public func showdetailviewcontroller(vc: uiviewcontroller, sender: anyobject?)
note comment in header:
// in horizontally-compact environment master view controller // or detail view controller sent showviewcontroller:sender: // message. if neither 1 of them provide implementation // method fall full screen presentation.
by "master view controller or detail view controller", means view controller shown, in case uitabbarcontroller. uitabbarcontroller not implement showviewcontroller()
because doesn't have enough information -- show view controller? add new tab, or replace old one, or what?
so, result, fallback, full-screen presentation. doubt want user experience.
later on, when size changes regular , split view controller expands, gets confused presentation , crashes. (see mean defaults not being good?)
one way fix implement delegate method handle showdetail
. when width compact, explicitly find view controller want put new view controller onto, , it. think want push onto nav controller in first tab:
func splitviewcontroller(splitviewcontroller: uisplitviewcontroller, showdetailviewcontroller vc: uiviewcontroller, sender: anyobject?) -> bool { if splitviewcontroller.traitcollection.horizontalsizeclass == .compact { // default implementation not handle properly. // find appropriate navigation controller , push onto it. // better have direct outlet appropriate navigation controller, // work example... if let tabbarcontroller = splitviewcontroller.viewcontrollers.first as? uitabbarcontroller { if let navcontroller = tabbarcontroller.viewcontrollers?.first as? uinavigationcontroller { navcontroller.pushviewcontroller(vc, animated: true) // handled "show detail", split view controller, // please don't else return true } } } // did not handle "show detail", split view controller, // please default behavior return false }
if that, want implement delegate method. when size changed regular, want handle "expand" popping view controller off of same nav controller, returning it:
optional public func splitviewcontroller( splitviewcontroller: uisplitviewcontroller separatesecondaryviewcontrollerfromprimaryviewcontroller primaryviewcontroller: uiviewcontroller) -> uiviewcontroller?