views:

82

answers:

1

Hi,

I'm a little stumped with an issue that I think goes back to my design. I'm constructing a TableViewController based on a mainly static set of rows (4) - using that as a basis for a UITableView. Each row will kick off varying different views (detail, and UITableViews)... In my managed object context for the top view I can easily nav to the associated detail view because it's in context (nickname).. I initially thought about simply having un related tables and a series of buttons that would fire off the views... But I ditched that idea. My main current issue is knowing how to switch MOC or to different fetchedresults controllers (which are by the way defined in each .m to fetch from different tables.

At the moment, I've got a switch inside of TableViewControler.m.. This snipit works:

enter - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

NSInteger switchval = indexPath.row;

switch (switchval) { case 0: // Nickname { //This version brings up a detailed view controller - NickNameDetail *controller = [[NickNameDetail alloc] initWithNibName:@"NickNameDetail" bundle:nil]; controller.fetchedResultsController = self.fetchedResultsController; controller.managedObjectContext = [self.fetchedResultsController objectAtIndexPath:indexPath]; [self.navigationController pushViewController:controller animated:YES];

break;

} case 1:
{
NextTableViewContoller *.... (etc)... here here

However, I can't figure out how to switch to a different context and get different rows.

meTableViewController.managedObjectContext = self.managedObjectContext; nickNameDetail.managedObjectContext = self.managedObjectContext; nextTableViewController.managedObjectContext = self.managedObjectContext;

Anyone run into a scenario like this before? Sorry, can't get the code formatter to behave.

Thanks!

A: 

In some cases it may be good/opportune to pass to the new view controller pushed on the navigation stack the MOC of your current view controller. However, you usually want to pass a newly created MOC. Do this as follows:

in your app delegate add the following method

- (NSManagedObjectContext*)createNewManagedObjectContext
{

    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init]; 
    [moc setPersistentStoreCoordinator:[self persistentStoreCoordinator]]; 
    return [moc autorelease];
}

in your view controller pass the MOC as follows

myAppDelegate *mainDelegate = (myAppDelegate *)[[UIApplication sharedApplication] delegate];
NSManagedObjectContext *mainMOC = [mainDelegate createNewManagedObjectContext]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) 
                                                         name:NSManagedObjectContextDidSaveNotification
                                                       object:mainMOC];

newViewController.managedObjectContext = mainMOC;

and then handle the notification as needed, here is an example

- (void)contextDidSave:(NSNotification *)notification
{

    [managedObjectContext mergeChangesFromContextDidSaveNotification:notification];
    [self.tableView reloadData];

}

You also need to define and use a different NSFetchedResultsController for each of your view controllers. This is because the data you want to fetch and display are, of course, different for each view controller (different entity, predicate etc). Simply define them in each implementation file. Here is an example:

- (NSFetchedResultsController *)fetchedResultsController {

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

    /*
     Set up the fetched results controller.
     */

    NSFetchRequest *request = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Context" inManagedObjectContext:managedObjectContext];
    [request setEntity:entity];

    if(self.project){
        // get the contexts for the project
        NSPredicate * predicate = [NSPredicate predicateWithFormat: @"projectName == %@", self.project.name];
        [request setPredicate:predicate];
    }

    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES selector:@selector(caseInsensitiveCompare:)];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
    [request 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:request managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;

    [aFetchedResultsController release];
    [request release];
    [sortDescriptor release];
    [sortDescriptors release];

    return fetchedResultsController;
}    

and then use the fetchedResultsController as needed. For instance, put this in your viewDidLoad method:

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) {
        // Handle error
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        exit(-1);  // Fail
    }
unforgiven
Thank you very much! I will give this a try. It does make sense on various levels. Sorry for my late reply, email notification in my prefs didn't seem to work...
chinjazz
Well, if you like the answer, consider voting it ;-)
unforgiven
Hi unforgiven, This approach actually works nicely. I just wired it up and only received 2 warnings: (1) Local declaration of 'mainDelegate' hides instance variable(2) 'myAppDeligate' may not respond to '-createNewManagedObjectContext'. I'll dig into that analysis, but I must say, I'm impressed!
chinjazz
I am interested in understanding this piece relative to the whole projects predicates. I don't have any predicates stated prior to this, but will no doubt after I get it. if(self.project){ // get the contexts for the project NSPredicate * predicate = [NSPredicate predicateWithFormat: @"projectName == %@", self.project.name]; [request setPredicate:predicate]; } .... You defeintely get my vote as answered! A very much appreciated thank you! :)
chinjazz
To solve the warnings: 1) change mainDelegate to something different (e.g. myDelegate) because you already have a variable named mainDelegate; 2) add in the header file for your app delegate the method - (NSManagedObjectContext*)createNewManagedObjectContext;
unforgiven
About predicates: a predicate is the way you tell to Core Data what data you want to fetch; in my example, the predicate allows fetching from the Context entity only those contexts whose associated project's name is the one I am specifying. You may want to read the associated documentation: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Predicates/predicates.html%23//apple_ref/doc/uid/TP40001798-SW1
unforgiven
One last question, and I might have this figured out before you have a chance to reply. I'm now drilling down to a detail view, and coming up with a view with empty fields... I have other detailed views that work and I know how to wire up via IB. I think I'm not passing this new MOC properly...Appreciate what you may have insights on in this journey.. :)
chinjazz
Simply create a new MOC and pass it as already shown in the example snipped I have posted if you need to add new objects in the detail view. Otherwise, if you simply need to show detail items, then you may pass the current MOC associated to the master view controller to the new view controller you are pushing on the stack. If you do not get back correct information, then it is probably not correct the way you fetch the data you want to show (wrong predicate or something else).
unforgiven