NSFetchedResultsController woes....ios4

Discussion in 'iOS Programming' started by DetartrateD, Mar 24, 2011.

  1. DetartrateD, Mar 24, 2011
    Last edited: Mar 24, 2011

    DetartrateD macrumors newbie

    Joined:
    Mar 24, 2011
    #1
    Firstly, what a fountain of knowledge this forum is, more like an oracle for novice coders like myself. Big respect to the creators, moderators and fellow coders " Helping to keep our sanity through the turmoil error's can cause".

    Please also excuse the lack of articulate expression I may purvey as I this is week 4 of my SDK endeavor.........I suppose u have all been there!

    OK, so here is the bugity bug.

    I have basically used the ready made CoreData Recipes' app that Apple kindly supply as a template and built my own version from the ground up using the same code.

    My version will run if i remove this error report from the code from my version of RecipeListTableViewController.m

    Code:
     - (void)viewDidLoad {
    // Configure the navigation bar
    self.title = @"Hall of fame!";
    
    self.navigationItem.leftBarButtonItem = self.editButtonItem;
    
    UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemA dd target:self action:@selector(add)];
    self.navigationItem.rightBarButtonItem = addButtonItem;
    [addButtonItem release];
    
    // Set the table view's row height
    self.tableView.rowHeight = 44.0;
    
    NSError *error = nil;
    if (![[self fetchedResultsController] performFetch:&error]) {
    
    /* Replace this implementation with code to handle the error appropriately.
    
    abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
    */
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
    }
    }
    
    This if removed as I say, will allow the app to run BUT without any data being forwarded to my TableView.

    I have narrowed the issue down to this part of my code again in my version of RecipeListTableViewController.m:


    Code:
    #pragma mark Fetched results controller
    
    - (NSFetchedResultsController *)fetchedResultsController {
    // Set up the fetched results controller if needed.
    if (fetchedResultsController == nil) {
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Fish" inManagedObjectContext:managedObjectContext];
    [fetchRequest setEntity:entity];
    
    // Edit the sort key as appropriate.
    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"species" ascending:YES];
    NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptors, 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:nil];
    aFetchedResultsController.delegate = self;
    self.fetchedResultsController = aFetchedResultsController;
    
    [aFetchedResultsController release];
    [fetchRequest release];
    [sortDescriptor release];
    [sortDescriptors release];
    }
    return fetchedResultsController;
    }
    
    
    I have manually checked the SQLite DB and the info appears to be getting written correctly (if I remove the above mentioned error tag, I can get to the 'Add recipe' page etc.) it just will not fetch the data to build the tableView grrrrrr.

    The debugger with bt shows as follows :
    Code:
    2011-03-24 09:18:38.242 iFishWiki[3376:207] -[UITableView key]: unrecognized selector sent to instance 0x5038000
    (gdb) bt
    #0 0x010fb5a8 in objc_exception_throw ()
    #1 0x00fa86fb in -[NSObject(NSObject) doesNotRecognizeSelector:] ()
    #2 0x00f18366 in ___forwarding___ ()
    #3 0x00f17f22 in __forwarding_prep_0___ ()
    #4 0x00db5c60 in -[NSFetchedResultsController initWithFetchRequest:managedObjectContext:sectionN ameKeyPath:cacheName:] ()
    #5 0x0000334b in -[BestFishTableViewController fetchedResultsController] (self=0x6027be0, _cmd=0x11d1c) at /Users/antonycollins/Documents/iFishWiki/Classes/BestFishTableViewController.m:201
    #6 0x00002aa7 in -[BestFishTableViewController viewDidLoad] (self=0x6027be0, _cmd=0x6fc49e) at /Users/antonycollins/Documents/iFishWiki/Classes/BestFishTableViewController.m:40
    #7 0x0038665e in -[UIViewController view] ()
    #8 0x00384a57 in -[UIViewController contentScrollView] ()
    #9 0x00395201 in -[UINavigationController _computeAndApplyScrollContentInsetDeltaForViewCont roller:] ()
    #10 0x00393831 in -[UINavigationController _layoutViewController:] ()
    #11 0x00394b4c in -[UINavigationController _startTransition:fromViewController:toViewControll er:] ()
    #12 0x0038f606 in -[UINavigationController _startDeferredTransitionIfNeeded] ()
    #13 0x004a7e01 in -[UILayoutContainerView layoutSubviews] ()
    #14 0x01e64451 in -[CALayer layoutSublayers] ()
    #15 0x01e6417c in CALayerLayoutIfNeeded ()
    #16 0x01e5d37c in CA::Context::commit_transaction ()
    #17 0x01e5d0d0 in CA::Transaction::commit ()
    #18 0x002db19f in -[UIApplication _reportAppLaunchFinished] ()
    #19 0x002db659 in -[UIApplication _runWithURLayload:launchOrientation:statusBarSty le:statusBarHidden:] ()
    #20 0x002e5db2 in -[UIApplication handleEvent:withNewEvent:] ()
    #21 0x002de202 in -[UIApplication sendEvent:] ()
    #22 0x002e3732 in _UIApplicationHandleEvent ()
    #23 0x018dca36 in PurpleEventCallback ()
    #24 0x00f88064 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FU NCTION__ ()
    #25 0x00ee86f7 in __CFRunLoopDoSource1 ()
    #26 0x00ee5983 in __CFRunLoopRun ()
    #27 0x00ee5240 in CFRunLoopRunSpecific ()
    #28 0x00ee5161 in CFRunLoopRunInMode ()
    #29 0x002dafa8 in -[UIApplication _run] ()
    #30 0x002e742e in UIApplicationMain ()
    #31 0x00001e80 in main (argc=1, argv=0xbfffefa0) at /Users/antonycollins/Documents/iFishWiki/main.m:13
    (gdb)
    
    
    Your help, advise and suggestions are greatly appreciated.

    If you need any further info, please ask!

    DetartrateD
     
  2. jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #2
    Please use the [ code] brackets, it's a hell reading the post like that.

    Here is an error too

    Code:
    UIBarButtonItem *addButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemA dd target:self action:@selector(add];
    should be (add) at the end, and if it's sending an (id) sender with it, should be (add:)
    And I recommand instead of releasing it after, do an autorelease of the button

    Like this

    Code:
    UIBarButtonItem *addButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemA dd target:self action:@selector(add)] autorelease];
    and remove the [addButtonItem release];


    For the rest of the fetched, I don't have alot of experience, so I must say sorry for that ^__ can't help there.
     
  3. DetartrateD thread starter macrumors newbie

    Joined:
    Mar 24, 2011
    #3
    Cheers buddy for the heads up, looks much better now!

    The @selector (add)] issue was a posting error not as it shows in the code in my project but well spotted!
     
  4. jnoxx macrumors 65816

    jnoxx

    Joined:
    Dec 29, 2010
    Location:
    Aartselaar // Antwerp // Belgium
    #4
    Well, the error is on the UITableView key.
    the NSFetchedController might be even ok, but ur trying to call Key on an UITableView, and that's the error, but those code is not on here ^_-
    And no problem.
    Don't forget the release problems etc
     
  5. ppilone macrumors 6502

    Joined:
    Jan 20, 2008
    #5
    As jnoxx pointed out - you're trying to send "key" to UITableView - which does not respond to that selector. You're most likely doing this somewhere in your UITableView delegate or data source implementations, which is why you're not seeing the issue when you comment out the fetched results controller code (no data means data source methods won't be called).

    Take a look at your data source and delegate implementations and see if you can spot the problem (or post them here for more help).
     
  6. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #6
    I think this may be your problem (can't be sure without seeing the rest of your code). If your fetchedResultsController is a property like this and you synthesized it, then you are ok and I'm barking up the wrong tree.

    Code:
    @property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
    
    If not what you are doing is creating aFetchedResultsController, assigning it to your fetchedResultsController, and then releasing it. So now you fetchedResultsController just points to some random memory that the OS may or may not use again. You then call some function on that random memory and maybe there is a UITableView there now? All of a sudden you're now sending a message for an NSFetchedResultsController to your UITableView.

    When I do lazy loading like this I like to setup the property like this...

    Code:
    @class MyClass (NSObject) {
    NSFetchedResultsController *fetchedResultsController_;
    }
    
    @property (nonatomic, readonly) NSFetchedResultsController *fetchedResultsController;
    
    The above code would then turn into this...

    Code:
    - (NSFetchedResultsController *)fetchedResultsController {
    ...
    NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:nil];
    aFetchedResultsController.delegate = self;
    fetchedResultsController_ = aFetchedResultsController;
    ...
    }
    
    - (void)dealloc {
    [fetchedResultsControsser_ release];
    [super dealloc];
    }
    
    Notice how I made my iVar fetchedResultsController_ and my property fetchedResultsController? This way I know exactly which one I'm using instantly.

    Also notice how I assigned the fetchedResultsController_ directly? fetchedResultsController is readonly, I don't want anything to be setting it except for the getter.

    Also notice how I dropped the release? I moved that to the dealloc method as I want my fetchedResultsController to stick around.

    Even if this doesn't turn out to be your problem, hopefully you still find it useful. There are many times you get random errors either the "doesn't respond to message" or an EXC_BAD_ACCESS when you over release an object. And they can be difficult to track down.
     
  7. DetartrateD thread starter macrumors newbie

    Joined:
    Mar 24, 2011
    #7
    Thank you all so far for the input, been away for a couple of days so appologies for the late reply ;)...............

    Seepal, i declared my fetchedResultsController as follows

    Code:
     
    
    @class Fish;
    @class FishTableViewCell;
    
    
    @interface BestFishTableViewController : UITableViewController  <FishAddDelegate, NSFetchedResultsControllerDelegate> {
    @private
    	NSFetchedResultsController *fetchedResultsController;
    	NSManagedObjectContext *managedObjectContext;
    	
    }
    
    @property (nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
    @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext;
    
    
    - (void)showFish:(Fish *)fish animated:(BOOL)animated;
    - (void)configureCell:(FishTableViewCell *)fishCell atIndexPath:(NSIndexPath *)indexPath;
    
    
    @end
    
    
    As you can see declared and synthesized as you had correctly hypothesized, although i have gone down the @private route (purely through inexperiance, this is the method used in the example code I have copied to some extent).

    ppilone, jnoxx, again thank you very much indeed for your input also. Here is my tableView method....


    Code:
    
    - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
        NSInteger count = [[fetchedResultsController sections] count];
        
    	if (count == 0) {
    		count = 1;
    	}
    	
        return count;
    }
    
    
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
        NSInteger numberOfRows = 0;
    	
        if ([[fetchedResultsController sections] count] > 0) {
            id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
            numberOfRows = [sectionInfo numberOfObjects];
        }
        
        return numberOfRows;
    }
    
    
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
        static NSString *FishCellIdentifier = @"FishCellIdentifier";
        
        FishTableViewCell *fishCell = (FishTableViewCell *)[tableView 
    																 dequeueReusableCellWithIdentifier:FishCellIdentifier];
        if (fishCell == nil) 
    	{
            fishCell = [[[FishTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:FishCellIdentifier] autorelease];
    		
    		fishCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
        }
    	[self configureCell:fishCell atIndexPath:indexPath];
    	
        return fishCell;
    	
    	}
    
    
    - (void)configureCell:(FishTableViewCell *)fishTableViewCell atIndexPath:(NSIndexPath *)indexPath {
        // Configure the cell
    	Fish *fish = (Fish *)[fetchedResultsController objectAtIndexPath:indexPath];
        fishTableViewCell.fish = fish;
    }
    
    
    
    - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    	Fish *fish = (Fish *)[fetchedResultsController objectAtIndexPath:indexPath];
        
        [self showFish:fish animated:YES];
    }
    
    
    // Override to support editing the table view.
    - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
        if (editingStyle == UITableViewCellEditingStyleDelete) {
    
    		NSManagedObjectContext *context = [fetchedResultsController managedObjectContext];
    		[context deleteObject:[fetchedResultsController objectAtIndexPath:indexPath]];
    		
    		// Save the context.
    	NSError *error;
    	if (![context save:&error]) {
    		NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    			abort();
    	}
    	}
    }
    	   
    

    I just cant find any noticeable issue, I hope it will be apparent to you more experienced guys!! Nomatter what, it has given e food for thought with regards releasing of objects at the correct time etc.

    TIA!

    DetartrateD
     
  8. seepel macrumors 6502

    seepel

    Joined:
    Dec 22, 2009
    #8
    What's the error you get when you try to fetch if you take out the abort functions? What if you tried a search on you code (cmd-f) for key?
     

Share This Page