Я думаю, что ваш диагноз, вероятно, неверный, но давайте представим на данный момент, что это не так, и посмотрим, что вы можете с этим поделать.
Если проблема заключалась в доступе к веб-представлению после освобождения в ответ на последовательность вызовов, показанную выше, то этот вызов будет поступать из updateDirectionsWithHtml:
через ссылку в self.directionsWebView
. В этом случае вы должны просто убедиться, что не держите устаревший указатель, а установите его на nil
. Тем не менее, я думаю, это справедливая ставка, что вы делаете уже делаете это, так что вряд ли это проблема.
Если проблема была в том, что к контроллеру обращались после освобождения, диспетчер местоположений вызвал метод делегата, то сначала вы должны разорвать связь. Что-то вроде [locationManager setDelegate:nil]
должно остановить нежелательный вызов, даже если диспетчер местоположений сам переживает ваш контроллер. Но опять же, я подозреваю, что вы уже выпускаете диспетчер местоположений до того, как контроллер умрет, и это тоже не проблема.
В этом случае проблема наиболее вероятна в другом месте, и, возможно, стоило бы рассмотреть сообщение об ошибке по номиналу: возможно ли, что где-то вы вызываете UIKit из фонового потока? Сказать, что среда выполнения смущена этим, потому что вы были в фоновом потоке ранее, кажется мне немного сомнительным. Эта ошибка выглядит так, как будто она исходит из чего-то конкретного. Это место может содержать ошибки, но обычно лучше начинать с предположения, что ОС работает лучше, чем собственный код.
Не видя остальную часть кода, трудно понять, где может быть настоящая проблема, если она действительно существует. Одна возможность, которая приходит на ум, заключается в том, что вы можете использовать невинно выглядящее свойство, которое на самом деле оказывается где-то в интерфейсе пользователя; но я признаю, что это просто пустые предположения.
Обновление:
Если перевод фонового вызова на передний план не позволяет вам нажать кнопку «назад», то операция, отнимающая много времени, уже должна выполняться, а это значит, что ваш метод делегата уже был вызван - запись в журнал сообщает вам, что просто нет не проходит.
Здесь мне приходит в голову то, что и performSelectorInBackground
, и performSelectorOnMainThread
сохраняют свой приемник до тех пор, пока селектор не завершит работу. Таким образом, время освобождения вашего контроллера, вероятно, искажено в результате (если вы не форсируете его из-за чрезмерного выпуска).
Из вашей трассировки стека это выглядит так, как будто dealloc
фактически вызывается из фонового потока как часть его собственной очистки. Затем он обращается к различным UIKit-объектам, что объясняет ошибку блокировки потока. Но если вызывается performSelectorOnMainThread
, это должно продлить срок службы контроллера, пока он не вернется в основной поток. Так, может быть, - это, в конце концов, переизбыток?
Обновление 2:
Эта дискуссия немного разбросана, но позвольте мне попытаться подвести итог тому, что, по моему мнению, происходит:
- Когда вы звоните
[self performSelectorInBackground:...]
, создается новый поток, и self
получает сообщение retain
потоком .
- Через некоторое время вы нажимаете кнопку "Назад" и заставляете ваш контроллер отправлять
release
. Однако, поскольку он был сохранен фоновым потоком, он еще не освобожден.
- Так или иначе фоновый поток завершает свою работу, после чего он отправляет
release
сообщение контроллеру. Число сохраняемых контроллеров падает до 0, и вызывается его метод dealloc
. Но так как это сообщение приходит из фонового потока, при попытке выполнить пользовательский интерфейс (удаление подпредставлений) вы получаете ошибку блокировки потока.
В обоснование этого последнего бита, который, как я понимаю, может показаться немного странным, обратите внимание, что в стеке вызовов после сбоя показаны вызовы, поступающие с завершения потока, а не с какой-либо обработкой событий, связанной с вашей кнопкой возврата.
Теперь интересный вопрос заключается не в том, почему фоновый поток отправляет release
, что является естественной частью его жизненного цикла, а в том, почему это уменьшает количество сохраняемых данных до 0. Если поток фактически достигает performSelectorOnMainThread
, должно быть еще одно retain
сообщение, и ваш контроллер должен выжить достаточно долго, чтобы освободить его в главном потоке, что должно быть хорошо.
Мне кажется, есть две возможные причины: либо преждевременный выход из потока, либо его чрезмерное освобождение. Но если бы он был последним, вы бы ожидали, что self
уже достигнет dealloc
до завершения потока.
Итак, я думаю, вопрос в том, может ли updateDirectionsWithHtml
выйти без вызова performSelectorOnMainThread
? Или, в противном случае, существует ли что-то еще, что может привести к преждевременному завершению потока?