#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 и соотношение сторон для высоты. Второй вид был размещен чуть ниже первого с ограничением расстояния по вертикали. После удаления вертикального интервала сбой исчез.