views:

2024

answers:

4

Hey!

I've been creating an iPhone App using Core Data.

First of all, does it make sense to use an NSFetchedResultsController and a UISearchDisplayController together to fetch the result? Would you recommend something else?

I've been trying quite long combining an NSFetchedResultController and a UISearchDisplayController. I've been thinking of setting an NSPredicate in the (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption method to the NSFetchedResultController of the UIViewController. But this isn't working that well.

So, have you any idea how to implement a solution for my problem? Thank you already for posting answers or links to good tutorials.

EDIT

Here is my code. The UISearchDisplayDelegate methods call the method (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope that should set the predicate in the NSFetchedResultController. I've also added the code of the NSFetchedResultController.

- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchString:(NSString *)searchString
{
    [self filterContentForSearchText:searchString scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:[self.searchDisplayController.searchBar selectedScopeButtonIndex]]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (BOOL)searchDisplayController:(UISearchDisplayController *)controller shouldReloadTableForSearchScope:(NSInteger)searchOption
{
    [self filterContentForSearchText:[self.searchDisplayController.searchBar text] scope:
     [[self.searchDisplayController.searchBar scopeButtonTitles] objectAtIndex:searchOption]];

    // Return YES to cause the search result table view to be reloaded.
    return YES;
}


- (void)filterContentForSearchText:(NSString*)searchText scope:(NSString*)scope
{
    NSString *query = self.searchDisplayController.searchBar.text;
    if (query && query.length) {
        NSPredicate *predicate = [NSPredicate predicateWithFormat:@"Name contains[cd] %@", query];
        [fetchedResultsController.fetchRequest setPredicate:predicate];
    }

    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }  

}


- (NSFetchedResultsController *)fetchedResultsController {

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    /*
     Set up the fetched results controller.
    */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];

    // Set the batch size to a suitable number.
    [fetchRequest setFetchBatchSize:20];

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"timeStamp" ascending:NO];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];

    [fetchRequest setSortDescriptors:sortDescriptors];

    // Edit the section name key path and cache name if appropriate.
    // nil for section name key path means "no sections".
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Root"];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];

    return fetchedResultsController;
} 
A: 

Try this tutorial:

http://blog.sallarp.com/iphone-core-data-uitableview-drill-down/

Grouchal
A: 

It sounds like you are just interested in fetching and displaying objects. In this case, you do NOT use a search display controller. The search display controller is used with a search bar to help with allowing user-entered text searches of your content.

Typically you use a fetched results controller to aid in your implementation of the table view datasource and delegate methods. Also, you create and use a fetch request for your fetched results controller. This is all boiler-plate (see the template code provided by Apple when you create a new project with the "Use Core Data for storage" option selected).

It is in the fetch request that you can create and specify a predicate. This will allow you to filter the objects that your table displays. For example:

// only fetch objects with myAttribute set to someValue
NSPredicate *pred = [NSPredicate predicateWithFormat:@"myAttribute == %@",someValue];
[fetchRequest setPredicate:pred];
gerry3
Well, I haven't mentioned clearly that I'm actually implementing a little search. I've already tried to set the predicate in the NSFetchedResultsController to filter the results, exactly like your posted code, but nothing happens, no objects are found. Any idea why the predicate doesn't work? It's just a simple comparison between the search string and the objects name. Thanks for help
burki
You should add details about the predicate or ask a new question about it. Also, it's always good to show the code you are using when asking questions.
gerry3
+6  A: 

Glancing at your code, its right there. I ran into issues using this method for changing the search. The fix: Clear your cache!

Say you initiated your fetched result controller as follows. Note the cacheName property.

    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:[self fetchRequest] managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"UserSearch"];

As you change your predicate, simply add:

 [NSFetchedResultsController deleteCacheWithName:@"UserSearch"];

Like magic, it will work nicely.

You will also want to monitor when the search display controller will end its search, and wipe your predicate.

Although this thread looks dead, I found it on google, so perhaps someone out there will get use of this. :)

A: 

According to the docs, you'll either want to filter the results into an array using a predicate or reinitialize the fetchedResultsController.

Important: You must not modify the fetch request after you have initialized the controller. For example, you must not change the predicate or the sort orderings.

-- NSFetchedResultsController

(I'd comment on idle's answer, but I'm karma-less.)

psuedonick