Я предполагаю, что вы устанавливаете некоторый объект (возможно, ваш контроллер представления) в качестве делегата вашего webView, либо через Interface Builder, либо через код, который выглядит примерно так:
- (void)viewDidLoad
{
[super viewDidLoad];
self.webView.delegate = self;
}
- (void)dealloc
{
[self.webView release];
[super dealloc];
}
В этом коде есть серьезная ошибка, которая не сразу очевидна, если вы не знаете, что искать. Вы можете это заметить?
Когда контроллер получает dealloc'd, он выпускает веб-представление, но это не обязательно означает, что веб-представление больше не существует. Это может все еще быть сохранено некоторым кодом внутри его внутренней реализации, и это может все еще загружать контент.
Когда загрузка завершится, веб-представление вызовет метод, подобный webViewDidFinishLoad:
, для своего делегата. Проблема в том, что ваш контроллер представления был делегатом, а ваш контроллер представления больше не существует. Раздел памяти, в котором использовался контроллер представления, был восстановлен операционной системой и больше не доступен для вашего процесса приложения. Хотя веб-представление этого не знает. У него все еще есть ссылка на этот адрес памяти в свойстве делегата. Поэтому он пытается вызвать метод делегата для этого объекта, и к сожалению ... EXC_BAD_ACCESS.
Подобные сбои выглядят случайными, поскольку они зависят от того, что ваше приложение делает в фоновом режиме в данный момент. Это делает их сложным для диагностики. К счастью, их легко решить. Просто установите делегат объекта равным nil до того, как вы отпустите его в свой оператор dealloc, например:
- (void)dealloc
{
self.webView.delegate = nil;
[self.webView release];
[super dealloc];
}
Задавая делегату веб-представления значение nil до его освобождения, вы гарантируете, что веб-представление не будет пытаться вызывать методы делегата для вашего объекта после его освобождения.
Если вы используете ARC, у вашего класса может не быть метода dealloc. Обычно это нормально, но в таком случае вы должны добавить его. Вы не хотите вызывать release
, если используете ARC, но вам все равно следует добавить метод dealloc и установить для свойства делегата значение nil.
Чтобы избежать подобных сбоев в будущем, применяйте эту рекомендацию каждый раз, когда вы устанавливаете свой объект в качестве делегата другого объекта.