ViewController отвечаетToSelector: сообщение отправлено освобожденному экземпляру (CRASH)

95

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

Хорошо, вот в чем проблема: мое приложение случайным образом включается и выключается из-за этой трассировки стека:

*** -[ViewController respondsToSelector:]: message sent to deallocated instance 0x1e5d2ef0

Где ViewControllerможет варьироваться, иногда место, где мой код дает сбой, НЕ имеет отношения к этому конкретному ViewControllerи не принадлежит или не называет его.

Кроме того, чтобы получить эту трассировку консоли, я включил Zombies, иначе я бы вообще не получил консольной печати, я бы получил только:, objc_msgSendчто, как я знаю, означает, что я отправляю сообщение о том, что выпущено. Но я не могу найти, где это ... Я действительно застрял! Обычно я всегда отлаживаю свои сбои, поэтому я действительно застрял на этом.

Опять же, это вылетает в разных местах в разное время, включается и выключается. А место падения почти не имеет отношения к ViewController. И меня это очень сбивает с толку.

Вам нужен мой код? У меня много файлов, и поскольку он дает сбой в разных местах, распространение моего кода будет затруднено!

Я безуспешно пытался добавить символические точки останова, а приложение «Зомби» недоступно в приложении «Инструменты» для iOS. Я не могу запустить свое приложение на симуляторе, так как для него есть неподдерживающая архитектура.

Спасибо всем...

MCKapur
источник
вы смотрели на этот вопрос: stackoverflow.com/questions/1585688/…
self
Предполагая, что способ перехода к своим взглядам согласован, возможно, вы сможете показать нам один или два примера. Если вы выполняете стандартные вызовы push / presentViewController, все должно быть в порядке, но я вижу, что многие люди здесь делают что-то вроде выделения / инициализации контроллера представления, но затем не делают push / present, а просто добавляют контроллер рассматривать как подвид. Просто случайный пример. Но мы не можем диагностировать это без кода. Надеюсь, несколько фрагментов кода помогут нам понять, что происходит, так что давайте посмотрим.
Роб
Как насчет включения символических точек останова? Попробуйте добавить эти: wiki.zemingo.com/index.php?title=Symbolic_Breakpoints
Ставаш
@RobertRyan Я использую presentModalViewController, я не добавляю его в качестве
подпредставления
В моем случае мой дочерний контроллер представления содержал webView, а дочерний VC был делегатом для scrollView webView. Мне нужно было вручную удалить ссылку на делегат во время dealloc / viewWillDisappear, иначе я получил этот сбой. Надеюсь, это кому-то поможет.
Дермот,

Ответы:

169

Используйте инструменты для отслеживания ошибок освобожденного экземпляра. Профилируйте свое приложение ( Cmd ⌘+ I) и выберите шаблон Zombies . После того, как ваше приложение запустится, попробуйте его вывести из строя. У вас должно получиться что-то вроде этого:

введите описание изображения здесь

Щелкните стрелку рядом с адресом во всплывающем окне, чтобы показать объект, который был вызван после того, как он был освобожден.

введите описание изображения здесь

Теперь вы должны видеть, что каждый вызов, который изменился, сохраняет счетчик этого объекта. Это может быть связано с отправкой напрямую сообщений о сохранении / освобождении, а также с истощением пулов автоматического выпуска или вставкой в ​​NSArrays.

Столбец RefCt показывает значение keepCount после того, как действие было вызвано, а Responsible Caller показывает имя класса и метод, в котором оно было выполнено. Когда вы дважды щелкаете по любому удержанию / освобождению, инструменты покажут вам строку кода, в которой это было выполнено (если это не сработает, вы можете проверить вызов, выбрав его и выбрав его аналог на панели расширенных сведений):

введите описание изображения здесь

Это позволит вам изучить весь жизненный цикл объекта keepCount и, вероятно, сразу же обнаружить свою проблему. Все, что вам нужно сделать, это найти недостающие остатки для последней версии .

Джонни
источник
3
Проблема может быть не самой последней release. Проблема какая-то неуравновешенная release. Я также могу просто быть неудачником в том, на retainчто вы указываете и на что ссылаетесь позже.
Ken Thomases
1
Кроме того, у меня нет шаблона инструментов Zombie, это может быть потому, что я использую Xcode Beta 4.5, я пока
перейду
2
О, зомби есть только в симуляторе iOS. Я НЕ МОГУ запускать симулятор iOS, некоторые из моих используемых фреймворков и библиотек не поддерживают эту архитектуру
MCKapur
Небольшая заметка. Это из того, что нового в xcode 5. «Шаблон инструмента Zombies был улучшен в Xcode 5 и теперь поддерживает использование на устройствах. Для использования Zombies на устройствах требуется iOS 7.» Эта записка, которую я принес тебе, и 2 часа моего драгоценного времени ...
nickfox
2
Что это значит, если наше приложение перестает давать сбой и перестает выдавать ошибку «сообщение отправлено освобожденному экземпляру», когда мы подключаем к нему этот инструмент? (Это как если бы «болезнь» исчезла, когда пациенту дали «диагностический тест».)
Пракситель
59

была аналогичная проблема. В моем случае viewController должен был получать события navigationController, поэтому он регистрировался как делегат контроллера навигации:

 self.navigationController.delegate = self;

Сбой происходит, когда этот контроллер был освобожден, но все еще оставался делегатом для контроллера представления. Добавление этого кода в dealloc не повлияло:

-(void) dealloc
{
    if (self.navigationController.delegate == self)
    {
        self.navigationController.delegate = nil;
    }

потому что в момент вызова dealloc контроллер представления уже удален из иерархии представлений, поэтому значение self.navigationController равно нулю, поэтому сравнение гарантированно не удастся! :-(

Решением было добавить этот код, чтобы обнаруживать, что виртуальный канал покидает иерархию представления непосредственно перед тем, как это действительно произойдет. Он использует метод, представленный в iOS 5, чтобы определить, когда представление выталкивается, а не отправляется.

-(void) viewWillDisappear:(BOOL) animated
{  
   [super viewWillDisappear:animated];
   if ([self isMovingFromParentViewController])
   {
      if (self.navigationController.delegate == self)
      {
           self.navigationController.delegate = nil;
      }
   }
}

Больше никаких сбоев!

программное обеспечение развивалось
источник
Мне тоже спасибо - понадобилось всего 4 часа поиска, чтобы найти этот пост.
daidai
Спасибо за публикацию, возникла та же проблема ^^
Тайрон
Как вы, люди, находите решения таких раздражающих вопросов? Снимаю шляпу !!
ViruMax
4

Для тех, кто не может ее решить, вот еще несколько приемов:

https://stackoverflow.com/a/12264647/539149

https://stackoverflow.com/a/5698635/539149

https://stackoverflow.com/a/9359792/539149

https://stackoverflow.com/a/15270549/539149

https://stackoverflow.com/a/12098735/539149

Вы можете запускать инструменты в Xcode 5, щелкнув всплывающее окно проекта -> Изменить схему ... Профиль -> Инструмент и выберите Распределения или Утечки, затем профилируйте свое приложение, затем остановите инструменты, нажмите кнопку информации в Распределении и «Включить обнаружение NSZombie» .

Однако для сообщений, поступающих непосредственно из потока com.apple.main, это, вероятно, ничего не покажет.

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

[viewController release];
viewController = NULL;

Проблема в том, что выпуск не устанавливает для переменной значение NULL.

Это означает, что установка для него значения NULL снова вызывает освобождение, уменьшение refcount и немедленное освобождение памяти до тех пор, пока не закончатся с ним переменные, которые ссылаются на viewController.

Так что либо включите ARC, либо убедитесь, что ваш проект постоянно использует release или NULL, но не оба сразу. Я предпочитаю использовать NULL, потому что тогда нет возможности сослаться на зомби, но это затрудняет поиск, где объекты выпускаются.

Зак Моррис
источник
4

Вчера я столкнулся с той же проблемой в iOS. Я сделал IAP в подпредставлении «О программе» приложения и добавил Transaction Observer в «О программе» viewDidLoad. Когда я покупаю в первый раз, проблем нет, но после того, как я вернусь в главное окно и снова вхожу в подпредставление для покупки, возникла проблема «сообщение отправлено на освобожденный экземпляр», и приложение разбилось.

- (void)viewDidLoad
{
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];                                           object:nil];
}

После удаления Transaction Observer в dealloc проблема решена.

- (void)dealloc
{
    // Even though we are using ARC, we still need to manually stop observing any
    // NSNotificationCenter notifications.  Otherwise we could get "zombie" crashes when
    // NSNotificationCenter tries to notify us after our -dealloc finished.

    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
Оуян Ён
источник
Он исправил мой сбой во время выполнения ... Я получал zombieобъект для покупок в приложении. После многих часов раскопок я нашел вот это ... БОЛЬШОЕ СПАСИБО, чувак.
Махендра
4

У меня была очень похожая проблема, и я понял, что это связано с набором делегатов контроллера навигации.

Ниже решена моя проблема,

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];

    if (self.navigationController.delegate != self) {
        self.navigationController.delegate = self;
    }
}

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];

    if (self.navigationController.delegate == self) {
        self.navigationController.delegate = nil;
    }
}
Thatzprem
источник
Спасибо!! была такая же проблема здесь.
pegpeg 06
2

Была такая же проблема в OS X.

Для решения этого недостаточно - (void)deallocметода, как уже сказал @SoftwareEvolved. Но, к сожалению - (void)viewWillDisappear, доступно только в версии 10.10 и новее.

Я представил собственный метод в своем подклассе NSViewController, в котором для всех зомби-опасных ссылок установлено значение nil. В моем случае это были NSTableViewсвойства ( delegateи dataSource).

- (void)shutdown
{
  self.tableView.delegate = nil;
  self.tableView.dataSource = nil;
}

Вот и все. Каждый раз, когда я собираюсь удалить представление из супервизора, необходимо вызывать этот метод.

Astoria
источник
2

У меня была та же проблема. Было трудно найти, какой делегат вызывает проблему, потому что он не указывает ни на одну строку или оператор кода. Поэтому я попробовал каким-то образом, может быть, это станет для вас полезным.

  1. Откройте файл xib и у владельца файла выберите в правой части меню «Показать инспектор соединений». Список делегатов, которые подозреваются, установить на ноль.
  2. (То же, что и в моем случае) Объект свойства, такой как Textfield, может создать проблему, поэтому установите для его делегатов значение nil.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
Надим
источник