UITableView - moveRowAtIndexPath вызывает утечку памяти

Обзор

  • В проекте iOS у меня есть UITableView, и я пытаюсь переместить строку UITableView.
  • В моей модели изменен порядок данных, поэтому я пытаюсь визуально показать это в таблице, поэтому я использовал метод UITableView moveRowAtIndexPath:toIndexPath:
  • Для этого я создал экземпляр NSIndexPath, который я передаю методу UITableView.

Когда происходит утечка

  • Когда вы создаете экземпляр NSIndexPath с помощью метода indexPathForRow: section: (как показано в разделе кода), а затем передаете его методу UITableView moveRowAtIndexPath: toIndexPath:, происходит утечка.

Примечание.

  • Я использую ARC (автоматический подсчет ссылок)
  • XCode 4.3.1
  • Я использовал Инструменты (меню Xcode - Продукт > Профиль), чтобы определить утечку памяти.

Код: (внутри UITableViewController)

NSIndexPath *newIndexPath = [NSIndexPath indexPathForRow:newRow inSection:0]; //leaking

[self.tableView beginUpdates];
[self.tableView moveRowAtIndexPath:originalIndexPath toIndexPath:newIndexPath]; //I think this causes the leak
[self.tableView endUpdates];

Шаги, которые я пробовал

  • Комментирование вызова метода moveRowAtIndexPath:originalIndexPath toIndexPath: предотвращает утечку памяти
  • Я вручную использовал CFRelease (не уверен, что это хорошая практика в среде автоматического подсчета ссылок)

    CFRelease((__bridge void *)toIndexPath);

Вопросы:

  • Почему это происходит? есть ли какое-нибудь решение?
  • Являются ли результаты утечки памяти прибора точными?
  • Есть ли ошибка в методе UITableView moveRowAtIndexPath:originalIndexPath toIndexPath:?
  • Можно ли использовать CFRRelease? Есть ли безопасный способ предотвратить сбой приложения в случае, если CFRelease попытается освободить память, которая уже была освобождена (см. точный код выше).

person user1046037    schedule 11.03.2012    source источник
comment
Я не уверен, что Instruments укажет на утечку памяти, если объект был разыменован, но не собран мусор, поэтому это комментарий, а не ответ. Вы пытались запустить [[NSGarbageCollector defaultInstance] collectExhaustively] после обновлений?   -  person Fls'Zen    schedule 20.03.2012
comment
спасибо за ответ, я делаю проект iOS, поэтому я не смогу попробовать сборку мусора. поправьте меня, если я ошибаюсь   -  person user1046037    schedule 20.03.2012


Ответы (2)


Код, который вы разместили, не должен приводить к утечке памяти в настройке ARC (и без ARC, если уж на то пошло).

Если вы действительно подозреваете ошибку (например, UITableView не может освободить объект NSIndexPath), вы, вероятно, можете попытаться вручную освободить его в качестве временного обходного пути. Однако вы уверены, что он просто не выпускает его после завершения анимации? Даже если у вас нет анимации, может случиться так, что объект indexPath не освобождается до тех пор, пока не попадет в цикл ожидания (это довольно часто встречается с компонентами GUI и, очевидно, также с автоматически освобождаемыми объектами).

Однако, чтобы подтвердить, что это действительно утечка, попробуйте выяснить, увеличивается ли память со временем в долгосрочной перспективе (возможно, UITableView придерживается своего последнего объекта indexPath, в котором это, вероятно, не будет проблемой) . Кроме того, попробуйте запустить отладчик с установленной переменной среды NSZombieEnabled. Это обнаружит и взломает отладчик, когда вы попытаетесь дважды освободить объект.

person Krumelur    schedule 20.03.2012
comment
Большое спасибо за ответ, я столкнулся с другой проблемой, я попробую NSZombieEnabled. - person user1046037; 21.03.2012

У меня недостаточно представителей, чтобы добавить комментарий, поэтому мне придется добавить ответ. Я тоже вижу эту утечку. Я НЕ использую ARC, и я не использую beginUpdates/endUpdates для обертывания одиночного вызова moveRowAtIndexPath:toIndexPath: Instruments заявляет об 32-байтовой утечке NSIndexPath всякий раз, когда я вызываю этот метод.

Вызов indexPathForRow:inSection: NSIndexPath должен возвращать автоматически освобожденный объект, который не нужно освобождать вручную. Я подозреваю, что moveRowAtIndexPath:toIndexPath: неправильно сохраняет объект, вызывая утечку.

Я добавил некоторый код отладки, чтобы регистрировать keepCount NSIndexPath до и после вызова moveRowAtIndexPath:toIndexPath: и получил 1 до (он находится в пуле автоматического выпуска, так что это ожидается) и 5 ​​после (определенно не ожидается, если он не был добавлен в пул автовыпуска еще 4 раза!)

Изменить: см. также https://devforums.apple.com/message/639904 (требуется Apple Developer учетная запись)

person Geoff Hackworth    schedule 09.04.2012