У меня есть два контроллера A представления и B. От A я перешел для просмотра контроллера B следующим образом:
// in View Controller A
// navigateToB method
-(void) navigateToB {
BViewController *bViewController =
[[BViewController alloc] initWithNibName: @"BView" bundle:nil];
bViewController.bProperty1 = SOME_STRING_CONSTANT;
bViewController.title = @"A TITLE OF A VC's CHOOSING";
[self.navigationController pushViewController: bViewController animated:YES];
[bViewController release]; //<----- releasing 0x406c1e0
}
В BViewController свойство bPropery1 определяется с копией как ниже (примечание, B также содержит UITableView и другие свойства):
@property (nonatomic, copy) NSString *bProperty1;
Все, казалось, хорошо работало при навигации назад и вперед между A и B. Это - пока я не добавил UISearchDisplayController к табличному представлению, содержавшемуся в BViewController. Теперь, когда я перешел из B, назад к A, сбоям приложения.
Отслеживание стека показывает то, что смотрит поисковый контроллер отображения, автовыпускаемый во время катастрофического отказа:
#0 0x009663a7 in ___forwarding___
#1 0x009426c2 in __forwarding_prep_0___
#2 0x018c8539 in -[UISearchDisplayController _destroyManagedTableView]
#3 0x018c8ea4 in -[UISearchDisplayController dealloc]
#4 0x00285ce5 in NSPopAutoreleasePool
Шоу NSZombies:
-[BViewController respondsToSelector:]: message sent to deallocated instance 0x406c1e0
И история malloc на этом указывает на bViewController, уже выпущенный в методе A navigateToB выше:
Call [2] [arg=132]: thread_a065e720 |start ... <snip>
..._sendActionsForEvents:withEvent:] | -[UIControl sendAction:to:forEvent:] | -
[UIApplication sendAction:to:from:forEvent:] | -[**AViewController navigateToB**] |
+[NSObject alloc] | +[NSObject allocWithZone:] | _internal_class_createInstance |
_internal_class_createInstanceFromZone | calloc | malloc_zone_calloc
Кто-то может дать мне какие-либо идеи о том, что происходит здесь? В navigateToB методе, когда-то bViewController выпущен (после pushViewController), это, должно быть это для bViewController. Ничто иное даже не знает об этом, поскольку это локально для navigateToB блока метода, и это было выпущено.
При навигации от B назад к A, ничто не вызывается в viewDidLoad, viewWillAppear и т.д., который повторно введет navigateToB.
Похоже так или иначе, что поисковый контроллер отображения имеет ссылку на что-то в моем AViewController и поэтому поскольку это автовыпущено, это берет этому "что-то" вниз с ним, но я не могу понять, как это возможно, тем более, что я использую копию для передачи данных между A и B.
Я иду горшочек по этому. Я уверен, что это - моя ошибка где-нибудь и таким образом, я обращаюсь к Вам, легендам Stack Overflow для любых слов мудрости или совета относительно того, как разрешить это.
Большое спасибо.
Когда вы надвигаете контроллер представления на контроллер навигации, контроллер навигации сохраняет контроллер представления. А когда этот контроллер представления разворачивается, контроллер навигации освобождает его.
Похоже, что UISearchDisplayController пытается проверить, реагирует ли ваш контроллер представления на селектор, и поскольку он вызывается из _destroyManagedTableView, я предполагаю, что селектором является searchDisplayController:willUnloadSearchResultsTableView: (ваш контроллер представления является делегатом контроллера отображения поиска, правильно?).
@robert - этот пример, должно быть, неправильный, потому что pushViewController действительно сохраняет свой аргумент. Все остальные примеры на странице либо автоотпускаются сразу после init, либо отпускаются после push.
Я решил аналогичную проблему, добавив эти строки в метод dealloc моего UITableViewController, который был делегатом UISearchDisplayController:
self.searchDisplayController.delegate = nil;
self.searchDisplayController.searchResultsDelegate = nil;
self.searchDisplayController.searchResultsDataSource = nil;
Меня немного смутило предложение, что для решения этой проблемы контроллер поискового дисплея должен быть освобожден в dealloc - то, что вам нужно сделать, это удалить указатели, которые контроллер поискового дисплея имеет на ваш контроллер представления таблицы, поскольку ваш контроллер представления таблицы теперь исчезает и не должен вызываться, когда ваш контроллер поискового дисплея позже будет освобожден. Это просто как любая другая ссылка на делегат, которую вы хотите уничтожить в dealloc.