Objective C, приложение вылетает при смене контроллера корневого представления. Осиротел без делегата (ошибка!)

#ios #objective-c #constraints #uncaught-exception #orphaned-objects

#iOS #objective-c #ограничения #неперехваченное исключение #сирота-объекты

Вопрос:

Я внедрил выпадающее меню в свое приложение для iOS, которое вызывает функции для навигации между различными раскадровками. Каждый элемент в этом меню вызывает следующую функцию в классе AppDelegate с другим именем раскадровки:

 (void)changeController:(NSString*)storyboardName
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle:[NSBundle mainBundle]];

    //initialize the new view
    currentView = [storyboard instantiateInitialViewController];
    currentView.view.alpha = 0.0;
    currentView.view.frame = currentView.view.bounds;
    currentView.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    //the app crashes on this line with a Thread 1: signal SIGARBT message
    self.window.rootViewController = currentView;
    [self.window makeKeyAndVisible];

    //animate with a fade transition
    [UIView animateWithDuration:transitionDuration
                          delay:0.0
                        options:UIViewAnimationOptionCurveLinear
                     animations:^{currentView.view.alpha = 1.0;}
                     completion:^(BOOL finished){}];
}
 

Проблема в том, что вызываемая функция приводит к сбою приложения непоследовательно. Это работает с одних экранов, а не с других. И что еще хуже, иногда он работает на экранах, на которых обычно выходит из строя.

Есть два сообщения об ошибках, которые выводятся на консоль, и они (я добавил разрывы строк для удобства чтения):

 Objective: {
 objective 0x15e4b3c0: <750:-1.64135e-05>   <750:8.34465e-08>
 *<orphaned without delegate (bug!):0x1703c790>{id: 188}   <750:4.17233e-08>
 *<orphaned without delegate (bug!):0x1703c980>{id: 192}   <750:-2.68221e-08>
 *UIView:0x170c6e40.Height{id: 1091}
}
 

и

 uncaught exception: <NSISEngine: 0x15e0b380>{ Rows:
    UIWindow:0x15db3160.Height{id: 140} == 960   1*0x15dd03e0.marker{id: 144}
    UIWindow:0x15db3160.Width{id: 137} == 640   1*0x15dd03b0.marker{id: 141}
    UIWindow:0x15db3160.minX{id: 136} == 0   2*0x15dd0200.marker{id: 135}   -0.5*0x15dd03b0.marker{id: 141}
    UIWindow:0x15db3160.minY{id: 139} == 0   2*0x15dd0350.marker{id: 138}   -0.5*0x15dd03e0.marker{id: 144}
    objective{id: 1} == {
         objective 0x15e4b3c0: <750:-1.64135e-05>   <750:8.34465e-08>
         *<orphaned without delegate (bug!):0x1703c790>{id: 188}   <750:4.17233e-08>
         *<orphaned without delegate (bug!):0x1703c980>{id: 192}   <750:-2.68221e-08>
         *UIView:0x170c6e40.Height{id: 1091}}

     Constraints:
         <NSAutoresizingMaskLayoutConstraint:0x15dd03b0 h=--- v=--- H:[UIWindow:0x15db3160(320)]>       Marker:0x15dd03b0.marker{id: 141}
         <NSAutoresizingMaskLayoutConstraint:0x15dd03e0 h=--- v=--- V:[UIWindow:0x15db3160(480)]>       Marker:0x15dd03e0.marker{id: 144}
         <_UIWindowAnchoringConstraint:0x15dd0200 h=--- v=--- UIWindow:0x15db3160.midX ==   160>        Marker:0x15dd0200.marker{id: 135}
         <_UIWindowAnchoringConstraint:0x15dd0350 h=--- v=--- UIWindow:0x15db3160.midY ==   240>        Marker:0x15dd0350.marker{id: 138}

    Integralization Adjustments:
         (none)

    Statistics:
    4 rows. Variable counts:
            1 ->   2
            2 ->   2
}: internal error.  Cannot find an outgoing row head for incoming head UIView:0x170c6e40.Height{id: 1091}, which should never happen.
 

Это последняя строка, которая меня действительно смущает: «внутренняя ошибка … которая никогда не должна произойти».

Мне любопытно, сталкивался ли кто-нибудь еще с этой ошибкой и как они ее устраняли.

  • Это проблема с инициализацией переменной currentView или, возможно, что-то связанное с переменной окна AppDelegate?
  • Действительно ли это проблема с ограничениями раскадровки? И если да, существует ли ограничение на количество ограничений, которые я могу / должен размещать на одном экране?

Редактировать:

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

Проблема была в конечном итоге решена, когда ограничения в нарушающем UIViewController были сняты и воссозданы заново.

Спасибо за всю вашу помощь и предложения.

Комментарии:

1. Я сделаю два предположения. 1) Попробуйте закомментировать переход к затуханию и просто изначально установите currentView.view.alpha значение равным 1. Меня беспокоит то, что предыдущее представление освобождается, как только вы устанавливаете rootViewController , и, следовательно, переход не работает. 2) Это многопоточная проблема с циклом сохранения. Некоторое подмножество старой иерархии представлений хранится в памяти, и фоновый поток ставит в очередь обновление для старой иерархии представлений после rootViewController того, как оно было изменено. Не знаете, как отследить это, кроме как выполнить проверку кода любой многопоточности в вашем приложении.

2. Я предполагаю, что к тому времени, когда вы получите эту последнюю ошибку, память будет довольно сильно потрепана.

3. Проблема сохраняется даже после комментирования перехода fade, но я думаю, что вы на что-то натолкнулись с асинхронным освобождением UIViews. Я попытался программно удалить все вложенные представления и могу воспроизвести ошибку в цикле удаления. Но сообщения журнала консоли отображаются не в том порядке, в котором я ожидал. Я прокомментирую еще раз, если сделаю прорыв.

4. Ваш комментарий в коде гласит «Поток 1» — это опечатка? Все это должно происходить в основном потоке (поток 0).

5. Я также столкнулся с той же проблемой. Во время навигации по переходу приложение просто вылетает с тем же журналом из вопроса. Начал играть с ограничениями начального viewcontroller (удаление частей пользовательского интерфейса по одному), сбой внезапно исчез. Не уверен, почему, но ограничения вызвали сбой. В моем случае проблема заключалась в вертикальном выравнивании двух представлений друг за другом. Сначала использовалась пропорциональная ширина для super view и соотношение сторон для высоты. Второй вид был размещен чуть ниже первого с ограничением расстояния по вертикали. После удаления вертикального интервала сбой исчез.