Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Since iOS 8 I'm experiencing a weird issue with a table view/UISearchBar setup and wondered if others have experienced a similar issue or can point to what, if anything, I might be doing wrong. The broad situation:

  • I have a UITableViewController with a UISearchBar within it, set up in the app's Storyboard
  • the table view has a custom cell, again, set up in the Storyboard
  • selecting a table row triggers a segue to another view
  • performing a search, tapping a row from the search results to segue to the other view, then navigating back again, triggers various issues.

"The issues" 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 by specifying the path to dequeueReusableCellWithIdentifier, then this results in a BAD_ACCESS or assertion failure in iOS 8 (but not iOS 7). Specifically, either an assertion failure or BAD_ACCESS occurs on calling dequeueReusableCellWithIdentifier under the circumstances mentioned above, i.e. when, with a search active, you segue from one of the cells in the results table to another view and then segue back again.

Now, I can stop the error occurring by just calling:

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

without passing in the indexPath. This then works without an error as such, but on segueing back to the table view with search results, a weird display issue occurs whereby layered underneath the search results, there appear to be the separators of a "ghost" table, almost as though the system is trying to render one table directly on top of another (but cellForRowAtIndexPath isn't being called for each table, only for the search results table as expected).

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

So: (a) can anyone point to something I might be doing wrong to cause these issues, or (b) point to a bare-bones working example of a table view controller with UISearchBar where the table cells segue to another view? I'm surprised I'm getting so many issues as implementing a searchable table with detail views must be a common, boring thing that people do all of the time, no?

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

like image 411
Neil Coffey Avatar asked Oct 29 '14 16:10

Neil Coffey


People also ask

Are the records in the views displayed properly?

The records in the views are displayed properly. While working on opportunity, quote, order, or invoice records, you might observe that some records are missing. You might not see some records because of an error that occurred due to customization done to the subgrid.

How do I resolve an issue with an existing view?

Before you start resolving the issue, take note of the view for which this issue is occurring. Go to Settings > Customizations > Customize the System. Select the Entity > Views and select the view that has this issue. In this example, we're selecting the table Account and view as Accounts Being Followed. Select More Actions > Edit.

What is the difference between viewbag and studentinformation view snippet?

The "StudentInformation" view snippet is from "StudentInformation.cshtml". ViewBag is dynamic property that takes advantage of new dynamic features in C# 4.0. It's also used to pass data from a controller to a view. In short, The ViewBag property is simply a wrapper around the ViewData that exposes the ViewData dictionary as a dynamic object.

Why doesn't the lookup field display products from the custom view?

If you change the default view of the lookup field to a custom view, the field doesn't display products from the custom view. To be able to display products from the selected price list, the lookup always defaults to a system view named Products in Parent Price List.


3 Answers

I Downloaded your code and what i observed is if i change the

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

method as follows it is working fine 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 it works for you and what my suggestion is use "NSPredicate" to filter the array like as follows.

- (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 NSArray not NSMutableArray.

The above solution is working for me Here is one more approach to solve 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;
}
like image 87
Logger Avatar answered Oct 23 '22 05:10

Logger


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

For the searchResultsTableView however, avoid specifying the indexPath as it's not necessarily valid for your view controller's tableView. That is:

- (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
}

For this to work correctly, you also need to amend your other UITableViewDataSource method. Instead of:

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

Do:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if ([tableView isEqual:self.searchDisplayController.searchResultsTableView]) {
        return searchResults.count;
    }
    return testData.count;
}
like image 28
followben Avatar answered Oct 23 '22 06:10

followben


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

When you search for "One", and clear all search text, there is only one visible cell left in self.tableView and no visible cell in UISearchResultsTableView. Actually at this time both tables should have no visible cells left. Then you search for "T", now there should be two cells in UISearchResultsTableView because "Two" and "Three" match "T", at this time, there is only one visible cell in self.tableView, which label text is "One",dequeueReusableCellWithIdentifier:forIndexPath works fine for row 0, for row 1, it crashes. I think the reason is that there is only one visible cell for self.tableView.

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

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

if (searchText.length == 0) {
    [self.tableView reloadData];
}
like image 44
gabbler Avatar answered Oct 23 '22 07:10

gabbler