I\'ve been trying to add simple Search functionality to a TableViewController in my app. I followed Ray Wenderlich\'s tutorial. I have a tableView with some data, I added th
The reason why it worked great on first run but then crashed if you exited the results table and went back in for another search is because the Search Display Controller is loading a new UITableView
each time you enter search mode.
By search mode I mean, you've tapped the textfield and you've began to type, at which point a table view is generated to display results, exiting this mode it achieved by hitting the cancel button. When you tap the textfield the second time and begin typing again - this is entering "search mode" for the second time.
So in order to avoid the crash you should register the cell class for the table view to use in the searchDisplayController:didLoadSearchResultsTableView:
delegate method (from UISearchDisplayDelegate
) of instead of in your controllers viewDidLoad
method.
As follows:
- (void)searchDisplayController:(UISearchDisplayController *)controller didLoadSearchResultsTableView:(UITableView *)tableView
{
[tableView registerClass:[DPContentTableCell class] forCellReuseIdentifier:cellIdentifier];
[tableView registerClass:[DPEmptyContentTableCell class] forCellReuseIdentifier:emptyCellIdentifier];
}
This caught me by surprise because on iOS 7... the table view is being reused. So you can register the class in viewDidLoad
if you prefer. For legacy sakes, I'll keep my registration in the delegate method I mentioned.
When I had this problem, the solution was replacing tableView
dequeueReusableCellWithIdentifier:@yourcell with self.tableView
for swift 3 you just need to add self:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = self.tableView.dequeueReusableCell(withIdentifier: "yourCell", for: indexPath) as! YourCell
...
}
Dequeue the cell without using the 'indexPath' and in case of you obtain a nil element, you have to allocate it manually.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"YourCellId"];
if (!cell)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"YourCellId"];
// fill your cell object with useful stuff :)
return cell;
}
Trying to use self.tableView for dequeue the cell may cause crashes when you have a sectioned main list and a plain search list. This code instead work in any situation.
Try using self.tableView instead of tableView in dequeueReusableCellWithIdentifier:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:@"BreedCell"];
//Create PetBreed Object and return corresponding breed from corresponding array
PetBreed *petBreed = nil;
if(tableView == self.searchDisplayController.searchResultsTableView)
petBreed = [_filteredBreedsArray objectAtIndex:indexPath.row];
else
petBreed = [_breedsArray objectAtIndex:indexPath.row];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = petBreed.name;
return cell;
}
This code works pretty well
Note
If you have custom height cells, do not use
[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
Use this instead
[self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
I am working on that tutorial also. The default TableViewController has "forIndexPath" and in his example it doesn't exist. Once I removed it the search works.
//Default code
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
//Replace with
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];