2016-06-01 3 views
7

У меня есть существующее приложение для iPhone, которое я добавляю UISplitViewController. Часть iPad работает как шарм, но у меня есть гарантированный крах с iPhone 6 (S) Plus.iPhone 4 Plus UISplitViewController crash с рекурсивным _canBecomeDeepestUnambiguousResponder

Установка - Мастер UITabBarController. Первоначальная деталь - это представление с видом логотипа-заполнителя. После выбора объекта деталь заменяется на UITabBarController.

Всякий раз, когда я выбираю элемент и открываю деталь в iPhone 6 Plus и поворачиваю его из портрета (только видимая деталь) в пейзаж (где мастер будет виден), он падает. Это не происходит при вращении с подробным представлением заполнителя.

Перед сбоем он вызывает методы делегата primaryViewControllerForExpandingSplitViewController и splitViewController(splitViewController: UISplitViewController, separateSecondaryViewControllerFromPrimaryViewController. Тем не менее, все работает отлично на iPad.

Я уже сделал тонну поиска и видел только пару твиттерных упоминаний об этом типе аварии. Такие вещи, как установка или отсутствие установки displayModeButtonItem, не помогают.

Я воссоздал эту аварию в свежем проекте - его можно скачать здесь: журнал https://github.com/sschale/SplitViewCrash/

Крушения:

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 

ответ

4

Это происходит сбой на IPad тоже. Используйте Multitasking для изменения размера приложения до компактной ширины (например, 1/3-й экран), нажмите кнопку «Launch Detail», а затем измените ее на обычную ширину.

Когда вы находитесь в компактной ширине, контроллер с разделенным изображением «рухнул». Это означает, что он больше не отображает отдельные первичные и вторичные контроллеры представлений одновременно, вместо этого он «сворачивает» их в единую иерархию контроллера представления. Когда это происходит в этой среде, вам часто нужна ваша помощь, чтобы действовать разумно. Поведение по умолчанию хорошо работает, когда ваш основной и вторичный контроллеры представлений являются UINavigationControllers, но не в других случаях.

(В вашем приложении ваш основной элемент - UITabBarController, а после того, как вы «Запуск детали» один раз, вторичным является также UITabBarController. Возможно, вам захочется пересмотреть этот дизайн, потому что это усложняет работу. Продолжайте читать.)

кнопку вашего приложения "Launch Detail" выполняет "Show Detail" SEGUE, который фактически вызывает этот метод на UISplitViewController:

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

Обратите внимание на комментарий в заголовке:

// 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. 

Под «контроллером главного представления или контроллером подробных представлений» это означает, что в настоящее время отображается контроллер вида, который в вашем случае является UITabBarController. Но UITabBarController ничего не реализует для showViewController(), потому что у него недостаточно информации - где бы он отображал контроллер вида? Будет ли он добавлять новую вкладку или заменить старую или что?

Итак, вы получаете эту резервную полноэкранную презентацию. Я сомневаюсь, что вы действительно хотите этого пользователя.

Позже, когда размер изменится на Регулярный, а контроллер разделенного вида расширится, он становится смущенным презентацией и в конечном итоге сбой. (Посмотрите, что я имею в виду, что значения по умолчанию не очень хорошие?)

Один из способов исправить это, чтобы реализовать метод делегата для обработки showDetail. Когда ширина Compact, явным образом найдите контроллер вида, на который вы хотите поместить новый контроллер просмотра, и сделайте это. Я думаю, что вы, вероятно, хотите, чтобы нажать на контроллер нав в первой вкладке:

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 
} 

Если вы сделаете это, вы также хотите, чтобы реализовать этот метод делегата. Когда размер будет изменен на «Обычный», вам нужно будет обработать «развернуть», выставив этот контроллер вида с того же навигационного контроллера, а затем вернув его:

optional public func splitViewController(
    splitViewController: UISplitViewController 
    separateSecondaryViewControllerFromPrimaryViewController 
     primaryViewController: UIViewController) -> UIViewController? 
+0

Спасибо за подробный ответ. Мой пользовательский интерфейс был первоначально «modal» segue для 'UITabBarController' после того, как запись была выбрана из исходного' UITabBarController' (но другие вкладки, необходимые для не-записей конкретных элементов), - и большинство моих приложений содержится в нем, поэтому переход был изменен на 'presentDetail'. Я все еще чувствую, что он работает относительно хорошо, как контроллер разделенного вида, но я не эксперт по пользовательскому интерфейсу. Я сделаю ваши предложения сегодня днем. Еще раз спасибо. – sschale

+0

Чтобы следить за тем, ваши предложения положили меня на правильный путь - мне в конечном итоге пришлось реализовать 4 свойства 'delegate' для достижения того, что я хочу. Теперь он работает (почти) отлично! – sschale

+0

Рад, что у вас это работает! –

Смежные вопросы