ViewController respondsToSelector: повідомлення надіслано звільненому екземпляру (CRASH)


95

Гаразд, ось угода, я ненавиджу висувати запитання про свої налагодження та збої. Оскільки я зазвичай з ними обробляю себе, але я просто не можу це обійти, навіть переглянувши кілька запитань .

Гаразд, ось у чому проблема, я вважаю, що мій додаток випадково вмикається і вимикається за допомогою цього трасування стека:

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

Де ViewControllerможе змінюватися, іноді місце, де мій код аварійно відображається, НЕ має відношення до цього конкретного товару ViewControllerі не є власником або не називає його.

Крім того, щоб отримати цей консольний контур, я увімкнув Zombies, інакше я б взагалі не отримував друк консолі, я б отримав лише:, objc_msgSendщо, як я знаю, означає, що я повідомляю щось, що було випущено. Але я не можу знайти, де це ... Я справді застряг! Зазвичай я завжди налагоджую свої збої, тому я справді на цьому застряг.

Знову ж таки, це падає в різних місцях у різний час, вмикається та вимикається. І місце, де воно падає, майже не має відношення до ViewController. І це мене дуже бентежить.

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

Я намагався додати символічні точки зупинки, не маючи удачі, і Zombies недоступний у програмі Instruments для iOS. Я не можу запустити свою програму на симуляторі, оскільки вона має непідтримувані архітектурні рамки.

Дякую всім...


Ви розглядали це питання: stackoverflow.com/questions/1585688/…
self

Якщо припустити, що спосіб переходу до ваших поглядів узгоджується, можливо, ви можете показати нам приклад чи два. Якщо ви робите стандартні дзвінки push / presentViewController, у вас повинно бути добре, але я бачу, що багато людей тут роблять такі речі, як alloc / init'ing контролер перегляду, але потім не роблять push / present, а просто додають контролер подання як підпрогляд. Просто випадковий приклад. Але ми не можемо діагностувати це без певного коду. Сподіваємось, кілька фрагментів допоможуть нам зрозуміти, що відбувається, так що давайте подивимось.
Роб

Як щодо включення символічних точок зупинки? Спробуйте додати такі: wiki.zemingo.com/index.php?title=Symbolic_Breakpoints
Ставаш

@RobertRyan Я використовую presentModalViewController, я не додаю його як підпрогляд
MCKapur

У моєму випадку мій дочірній контролер подання містив webView, а дочірній ВК був делегатом scrollView webView. Мені потрібно було вручну видалити посилання на делегат під час dealloc / viewWillDisappear, або я отримав цю аварію. Сподіваюся, це комусь допоможе.
Dermot

Відповіді:


169

Використовуйте інструменти, щоб відстежувати помилки звільнених екземплярів. Профілюйте свою заявку ( Cmd ⌘+ I) і оберіть шаблон Zombies . Після запуску вашої програми спробуйте розбити її. Ви повинні отримати щось подібне:

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

Клацніть на стрілку поруч із адресою в покажчику, щоб показати об'єкт, який був викликаний після вивільнення.

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

Тепер ви повинні бачити кожен виклик, який змінився, зберегти кількість цього об'єкта. Це може бути через те, що надсилати повідомлення про збереження / вивільнення безпосередньо, а також зливати пули автовипуску або вставляти в NSArrays.

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

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

Це дозволить вам вивчити весь життєвий цикл об’єкта retainCount і, ймовірно, ви одразу знайдете свою проблему. Все, що вам потрібно зробити, це знайти зниклий файл для останнього випуску .


3
Проблема може бути не останньою release, зокрема. Проблема в тому , будь незбалансований release. Я також можу бути просто невдалою для retainчогось, на що ви тримаєте вказівник і посилаєтесь пізніше.
Ken Thomases

1
Крім того, у мене немає шаблону інструментів Zombie, можливо, тому, що я використовую Xcode Beta 4.5, я тим часом
перейду

2
О, зомбі доступні лише в iOS-симуляторі. Я НЕ
МОГУ

Лише невеличка примітка. Це з новин у 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 дорівнює нулю, тому порівняння гарантовано не вдасться! :-(

Рішенням було додати цей код для виявлення VC, який покидає ієрархію подання безпосередньо перед тим, як він насправді це робить. Він використовує метод, введений в 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 знову викликає випуск, зменшення числа перерахунку та звільнення пам'яті негайно до пізніше, коли змінні, що посилаються на viewController, закінчаться з нею.

Тож увімкніть ARC або переконайтесь, що ваш проект послідовно використовує випуск або 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об’єкт для покупок inApp. Після багатьох годин копання я знайшов цього .... ВЕЛИКЕ ДЯКУЮ Чоловіку.
Махендра

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;
    }
}

Дякую!! тут була та сама проблема.
pegpeg

2

Була така сама проблема в OS X.

Для вирішення цього недостатньо - (void)deallocметоду, як уже було сказано @SoftwareEvolved. Але, на жаль - (void)viewWillDisappear, доступний лише у версії 10.10 та пізнішої.

Я представив власний метод у своєму підкласі NSViewController, де встановив для всіх зомбі-небезпечних посилань значення нуль. У моєму випадку це були NSTableViewвластивості ( delegateі dataSource).

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

Це все. Кожного разу, коли я збираюся видалити подання із суперперегляду, потрібно викликати цей метод.


2

У мене була та сама проблема. Важко було знайти проблему, яка причиною є делегат, оскільки вона не вказує жодного рядка чи твердження коду, тому я спробував якось, можливо, це стане для вас корисним.

  1. Відкрийте файл xib і у власника файлу виберіть "Показати інспектор з'єднань" праворуч. Делегати перераховані, встановіть їх на нуль, які є підозрюваними.
  2. (Те саме, що в моєму випадку) Об’єкт властивості, як Textfield, може створити проблему, тому встановіть для його делегатів значення нуль.
-(void) viewWillDisappear:(BOOL) animated{

[super viewWillDisappear:animated];

if ([self isMovingFromParentViewController]){

self.countryTextField.delegate = nil;

self.stateTextField.delegate = nil;

}

}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.