Приложение Iphone аварийно завершает работу при выпуске контроллера представления, содержащего прокрутку UITableView - PullRequest
2 голосов
/ 17 февраля 2011

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

Предположим, у меня контроллер навигации в качестве контроллера верхнего вида.Внутри него в какой-то момент у меня есть UIViewController, скажем, ContactsScreenController.Представление для этого содержит несколько UITableView, каждый из которых управляется отдельным объектом типа MyTableController (делегат и источник данных).Я делаю это, сохраняя массив контроллеров


// This is the interface for my screen controller. An object of this type goes in a top-
// level navigation controller
// MainScreenController.h
@interface ContactsScreenController : UIViewController

    NSMutableArray* tableControllers;

@end



// MainScreenController.m

- (UITableViewCell*)cellForRowAtIndexPath..something..
{
    // Here what I do is create a new controller if needed, and add it to tableControllers
    // Memory allocations & releases are good because I checked with instruments
}

#define SAFE_DEL(x)   { if (x != nil) { [x release]; x = nil; } }

- (void)dealloc
{
    SAFE_DEL(tableControllers);
    [super dealloc];
}

Теперь MyTableController - более сложный объект, так как он обрабатывает выборку данных из веб-службы, но в основном я хочу получитьчтобы убедиться, что при удалении объекта я отменяю все ожидающие запросы данных, например:


// MyTableController.m
- (void)dealloc
{
    [globalDataProvider cancelRequestsForController:self];

    // release other objects i might have
    [super dealloc];
}

ОК, так что это моя установка объектов.Сбой происходит, когда я удаляю объект tableControllers.Он уменьшает значение retainCount для моих объектов MyTableController и достигает 0 (проверено с помощью инструментов).Но по какой-то НЕИЗВЕСТНОЙ причине я получаю вызовы для cancelRequestsForController, ПОСЛЕ того, как количество сохранений было равно нулю.Очевидно, я получаю EXC_BAD_ACCESS.

Прежде чем вы начнете думать, что это проблема с моими парами сохранения / разблокировки, приложение работает отлично, если я освобождаю контроллер основного экрана, в то время как внутренние таблицы статичны.Как только прокрутка прокручивается, и я нажимаю кнопку «Назад» в контроллере навигации, я обнаруживаю ошибку.

Я проверил с помощью инструментов всю историю изменений счетчика сохранения для моих внутренних контроллеров, и это хорошо (нетнеобычные вещи).Когда возникает ошибка, моя последняя запись в истории происходит из QuartzCore run_animation_callbacks со счетом сохранения -1.

Есть идеи?:)

PS: В качестве быстрого решения для запуска проекта я переместил cancelRequestsForController в отдельный метод и вручную вызываю его для каждого объекта в tableControllers перед выпуском.Таким образом, я уверен, что после выпуска не будет звонков, независимо от состояния таблицы.


- (void)dealloc
{
    for (TableController* c in tableControllers)
        [c cancelRequests];
    SAFE_DEL(tableControllers);
    [super dealloc];
}

Но мне не нравится это решение по нескольким причинам.

Ответы [ 3 ]

2 голосов
/ 02 марта 2011

Спасибо всем за ответы / комментарии.
Проблема была вызвана вызовом [super dealloc] в объекте, прежде чем я получил возможность освободить свои объекты.Это вызвало много сумасшедших вещей.Я переместил [super dealloc] в конце моего метода dealloc (после моих выпусков), и теперь он работает нормально.

1 голос
/ 17 февраля 2011

Макрос SAFE_DEL не нужен и делает код менее читабельным.Просто сделайте:

[someObject release], someObject = nil;

Не имеет значения, если someObject уже равен нулю, и это делает код более читабельным.

Как только прокрутка и янажмите кнопку «Назад» в контроллере навигации. Я обнаружил ошибку.

Каждый раз, когда у вас есть логика управления, не связанная с памятью, у вас появляется хрупкость.А именно, когда выполняется dealloc, это весьма вероятно, потому что в вашем приложении есть целый подграф объектов, которые освобождаются.Поскольку порядок освобождения в значительной степени недетерминирован, вы не можете безопасно вызывать любое сложное поведение в dealloc без риска того, что вы собираетесь отправить сообщение уже dealloc объекту.

Лучшим решением было бы получить механизм отмены из dealloc!

0 голосов
/ 17 февраля 2011

Необходимо проверить две вещи: 1. имеет ли ваш globalDataProvider (или любой другой класс в этом отношении) ссылку на ваш контроллер (т. Е. Чтобы перезвонить ему с данными?). Количество сохраняемых данных может быть нулевым, но по неправильной причине.Как вы распределяете массив, а также каждый контроллер в массиве?У вас есть @ свойства?2. В окне «Аргументы» свойств исполняемых файлов установите NSZombieEnabled = YES, который точно скажет, какой объект вызывается, когда он имеет нулевое число удержаний.HTH, -Майк

...