2012-06-20 3 views
2

В проекте, над которым я работаю (я взял этот код, и я пытался его отладить), у меня есть функция, вызываемая наблюдателем. Наблюдатель вызывает метод, который обновляет данные, которые должны быть помещены на экран. Хотя это обновление происходит (требуется несколько секунд для обновления), пользователь может нажать кнопку «Назад» на панели навигации, что вызывает вызов dealloc. Пока этот метод запущен, вызов dealloc освобождает все ivars, что в конечном итоге вызывает EXC_BAD_ACCESS, когда метод пытается получить доступ к ivars. Структура метода обновления также прилагается к блоку @synchronized.Dealloc вызывается, пока метод все еще запущен

- (void)update { 

@synchronized(self){ 
    // some code here... 
    // Also access ivars here. 
    } 

} 

Что можно сделать, чтобы сообщить контроллеру закончить метод сначала перед освобождением? Я попытался запустить цикл while с условием в dealloc, но это не кажется эффективным. Он также никогда не выполняется полностью, если контроллер освобожден и находится в тупике. Я чувствую, что решение прост, но мой мозг жарится с длинного рабочего дня, и я не могу думать об этом.

ответ

2

Вы можете позвонить по телефону retain по телефону self, чтобы гарантировать, что счетчик ссылок не достигнет нуля при использовании более длительного действия; и избежать dealloc таким образом:

- (void) update { 
    [self retain] 

    // do work ... 

    [self release] 
} 
+0

Обратите внимание, что вы не можете сделать это под автоматическим подсчетом ссылок. – benzado

+0

Это решило проблему для меня! Я не понимал, насколько это было глупо. Благодаря! – SpacePyro

1

Если поставить работу, которую нужно сделать в блоке, компилятор будет автоматически сохранять все объекты, на которые ссылается внутри блока (включая себя). Например:

- (void)update { 
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{ 
     // some code here, access ivars, do whatever you want 
    }]; 
} 

Способ обновления будет немедленно возвратить и блок будет запланирован для запуска на главном цикле выполнения (нет вторичных потоков не участвуют здесь).

Если работа по обновлению является долговременной задачей, вы можете использовать фоновую очередь вместо основной, а затем (внутри этого блока) планировать другой блок для запуска в главной очереди и взаимодействовать с пользовательским интерфейсом, когда работа сделана.

0

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

Что бы я хотел сделать, так это то, что я бы сохранил ссылку на ViewController, с которой вы работаете вне навигационного контроллера, чтобы он не освобождался, когда пользователь нажимает кнопку «Назад».

Затем, если пользователь вернется к тому же самому виду, у вас уже будут загружены данные. Просто нажмите его снова, используя ту же ссылку.

Пример:

@interface YourRootViewController : UIViewController { 
    YourNextControllerClass *nextController; 
} 

@property (nonatomic, retain) YourNextControllerClass *nextController; 

@end 

В ViewDidLoad вашей верхней ViewController:

self.nextController = [[[YourNextControllerClass alloc] initWithNibName:@"YourNextControllerNib" bundle:nil] autorelease]; 

Если вы хотите, чтобы показать вид:

[myNavigationController pushViewController:nextController animated:YES]; 

Если пользователь нажимает кнопку назад , viewcontroller не будет выпущен, поэтому, когда вы нажмете его снова, все будет там, когда вы его покинете.

0

Решение зависит от того, хотите ли вы сохранить этот объект до конца метода или нет. Тем не менее, вы также используете @synchronized (self): я бы очень боялся, что произойдет, если self будет освобожден, а @synchronized попытается удалить блокировку на себе, поэтому в этом случае я попытаюсь сохранить ее в живых. (Тем не менее, @synchronised, а затем запускать много кода, на мой взгляд, не очень хорошая идея, @synchronised следует использовать для наименьшего количества кода, чтобы избежать взаимоблокировок).

С ARC, поддерживая объект в рамках метода, просто.

typeof (self) myself = self; 

создаст сильную ссылку на себя. И лучше использовать себя в теле метода вместо себя.

Если вы не хотите, чтобы объект «я» живым, который был бы обычный случай:

__weak typeof (self) weakSelf = self; 

Тогда везде, где вы хотите, чтобы убедиться, что само по-прежнему там вы пишете

typeof (self) strongSelf = weakSelf; 
if (strongSelf != nil) { 
} 
Смежные вопросы