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

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

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

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

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

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

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

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

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

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

Ответ 1

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

enter image description here

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

enter image description here

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

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

enter image description here

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

Ответ 2

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

 self.navigationController.delegate = self;

Авария происходит, когда контроллер отключен, но все еще является делегатом для контроллера вида. Добавление этого кода в dealloc не имело эффекта:

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

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

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

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

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

Ответ 3

Для тех, кто не может его решить, вот некоторые другие методы:

fooobar.com/questions/60399/...

fooobar.com/questions/60401/...

fooobar.com/questions/60402/...

fooobar.com/questions/60403/...

fooobar.com/questions/60405/...

Вы можете запускать Инструменты в Xcode 5, щелкнув всплывающее окно проекта → Изменить схему... Профиль → Инструмент и выберите "Распределения" или "Утечки", затем профиль вашего приложения, затем остановите "Инструменты", нажмите кнопку "Информация" в "Выделения" и "Включить NSZombie Detection".

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

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

[viewController release];
viewController = NULL;

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

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

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

Ответ 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;
    }
}

Ответ 5

Я столкнулся с той же проблемой в iOS вчера. Я сделал IAP в приложении "О себе", и я добавил Transaction Observer в "About" 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];
}

Ответ 6

Имела ту же проблему в OS X.

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

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

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

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

Ответ 7

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

  • Откройте файл xib и владельца файла, выберите "показать инспектора соединений" в правой части меню. Делегаты перечислены, установите их на нуль, которые подозреваются.
  • (То же, что и в моем случае) Свойство Object, подобное текстовому полю, может создать проблему, поэтому установите его делегаты на нуль.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}