Display issue when using UISearchBar with a table view controller and switching to another view

With iOS 8, I am having a weird problem with setting up the / UISearchBar table and wondering if others have a similar problem or might indicate that, if you like, I could be wrong. Wide situation:

  • I have a UITableViewController with a UISearchBar inside it, configured in a Storyboard application
  • The table view has a custom cell configured again in the storyboard
  • table row selection causes a spread in another view
  • doing a search, clicking a line from the search results to go to another view, and then moving again, causes various problems.

The "problems" are that if I implement cellForRowAtIndexPath as follows:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MyCell *cell = (MyCell *) [self.tableView dequeueReusableCellWithIdentifier:@"MyId" forIndexPath:indexPath]; ... 

in other words, specifying the path to dequeueReusableCellWithIdentifier will result in a BAD_ACCESS error or statement in iOS 8 (but not iOS 7). In particular, either a refusal of approval or BAD_ACCESS occurs when the dequeueReusableCellWithIdentifier is called in the above circumstances, that is, when you actively search, you move from one of the cells in the results table to another view and then leave again.

Now I can stop the error that occurs when calling:

  - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MyCell *cell = (MyCell *) [self.tableView dequeueReusableCellWithIdentifier:@"MyId"]; ... 

without going through indexPath. Then it works without error as such, but when we go to the presentation of the table with the search results, there is a strange display problem in which the layers below the search appear as ghost table separators, almost as if the system is trying to display one table directly on top the other (but cellForRowAtIndexPath is not called for each table, only for the search results table, as expected).

I get the same problem whether segue is related to a cell or table controller (so in the latter case, I implement didSelectRowAtIndexPath to manually run segue).

So: (a) can someone point out what I can do wrong to cause these problems, or (b) point to the open source desktop of the table view controller with UISearchBar, where the table cells go into another view? I am surprised that I am having so many problems, because implementing a searchable table with detailed views should be a normal, boring thing that people do all the time, no?

Sample project showing iusse: http://www.javamex.com/DL/TableTest.zip

+6
source share
4 answers

There is actually nothing wrong with using any method to deactivate your cell for the main tableView , although the indexPath option seems to be Apple's preferred option these days.

However, searchResultsTableView not specify indexPath for searchResultsTableView, as it is not necessarily valid for your tableView view tableView . I.e:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { MyTableViewCell *cell; if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) { cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell"]; } else { cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath]; } // configure the cell } 

To work correctly, you also need to change another UITableViewDataSource method. Instead:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return (searchResults) ? (searchResults.count) : (testData.count); } 

make:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) { return searchResults.count; } return testData.count; } 
+2
source

I downloaded your code and I noticed that if I changed

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 

since it works great for me.

Solution1:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (tableView == self.searchDisplayController.searchResultsTableView) { return [searchResults count]; } else { return [testData count]; } } 

Please let me know if this works for you and that my suggestion uses "NSPredicate" to filter the array as shown below.

 - (void) searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText { NSLog(@"Search text did change"); NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", searchText]; searchResults = [testData filteredArrayUsingPredicate:resultPredicate]; } 

Nlote: Take "searchResults" as an NSArray, not an NSMutableArray.

The above solution works for me. Here is another approach to solving the problem.

Solution2:

 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (tableView == self.searchDisplayController.searchResultsTableView) { return [searchResults count]; } else { return [testData count]; } } - (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope { NSPredicate *resultPredicate = [NSPredicate predicateWithFormat:@"SELF contains[cd] %@", searchText]; searchResults = [testData filteredArrayUsingPredicate:resultPredicate]; } // I implemented The following delegate method. -(BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString { [self filterContentForSearchText:searchString scope:[[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]]; return YES; } 
+5
source

Actually there are two table views, UISearchResultsTableView for displaying the result, self.tableView for displaying the source data.

When you search for "One" and clear all the search text, only one visible cell remains in self.tableView , and there is no visible cell in UISearchResultsTableView . In fact, at this time, both tables should not have visible cells. Then you search for โ€œTโ€, now in UISearchResultsTableView should be two cells, because โ€œTwoโ€ and โ€œThreeโ€ correspond to โ€œTโ€, currently in self.tableView there is only one visible cell, the text of which is โ€œOneโ€, dequeueReusableCellWithIdentifier:forIndexPath works fine for line 0, for line 1 it will work. I think the reason is that for self.tableView there is only one visible cell.

 MyTableViewCell *cell; if (tableView != self.tableView) { cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell"]; } else { cell = [self.tableView dequeueReusableCellWithIdentifier:@"MyCell" forIndexPath:indexPath]; } 

And in textDidChange, add this to the end to clear the tableView when searchText is an empty string.

 if (searchText.length == 0) { [self.tableView reloadData]; } 
+2
source

Having tried several approaches, I advise you to avoid dealing with the Apple API.

UISearchDisplayController manages its own UITableView , in addition to your main table. The cell id in the filtered table does not match your primary table.

As detailed here: UISearchDisplayController and UITableView prototype cell corruption


So the best approach is the one you already discovered:

 MyCell *cell = (MyCell *) [self.tableView dequeueReusableCellWithIdentifier:@"MyId"]; 

As for the ghost table separators, which, unfortunately, I could not reproduce, I would deal with this as follows:

 self.searchDisplayController.searchResultsTableView.separatorColor = [UIColor clearColor]; 

Good luck.

+2
source

Source: https://habr.com/ru/post/977423/


All Articles