Как может автовыделение UISearchDisplayController вызвать сбой в другом контроллере представления? - PullRequest
11 голосов
/ 03 мая 2010

У меня есть два контроллера представления 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, уже выпущенный в методе navigateToB A выше:

    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, и, поскольку он автоматически высвобождается, он забирает это «что-то», но я не могу понять, как это возможно, тем более что я использую копию передавать данные между А и В.

Я схожу с ума по этому поводу. Я уверен, что это где-то моя ошибка, и поэтому я обращаюсь к вам, легенды о переполнении стека, за любые слова мудрости или советы, как решить эту проблему.

Большое спасибо.

Ответы [ 3 ]

32 голосов
/ 16 июля 2010

У меня была похожая проблема, решенная добавлением этих строк в метод dealloc моего UITableViewController, который был делегатом UISearchDisplayController:

self.searchDisplayController.delegate = nil;
self.searchDisplayController.searchResultsDelegate = nil;
self.searchDisplayController.searchResultsDataSource = nil;

Меня слегка смутило предположение, что для решения этой проблемы контроллер дисплея поиска должен быть освобожден в dealloc - вам нужно просто удалить указатели, которые контроллер дисплея поиска имеет на вашем контроллере табличного представления, так как ваше табличное представление контроллер теперь уходит и не должен вызываться, когда ваш контроллер отображения поиска будет выпущен позже. Это как любая другая ссылка на делегат, которую вы хотите обнулить в dealloc.

5 голосов
/ 03 мая 2010

Когда вы помещаете контроллер вида в контроллер навигации, контроллер навигации сохраняет контроллер представления. И когда этот контроллер представления отключен, контроллер навигации освобождает его.

UISearchDisplayController, похоже, пытается увидеть, реагирует ли ваш контроллер представления на селектор, и, поскольку он вызывает _destroyManagedTableView, я предполагаю, что селектор - searchDisplayController: willUnloadSearchResultsTableView: (ваш контроллер представления является делегатом контроллера дисплея поиска, верно? ).

@ robert - этот пример должен быть неверным, потому что pushViewController сохраняет свой аргумент. Все остальные примеры на странице либо автоматически выпускаются сразу после init, либо освобождаются после нажатия.

3 голосов
/ 28 сентября 2011

У меня была такая же проблема. Элемент searchDisplayController не был равен нулю в зацеплении контроллера View, в котором он использовался. Вместо этого делегат управлял выпуском searchDisplayController, и это было сделано после того, как tableView был выпущен. Теперь, после ручного ввода этого кода в dealloc контроллера представления, теперь он работает нормально.

self.searchDisplayController.delegate = nil; self.searchDisplayController.searchResultsDelegate = nil; self.searchDisplayController.searchResultsDataSource = nil;

Спасибо за вашу помощь.

...