CoreData - newbie needs help

Discussion in 'iOS Programming' started by LostInTheTrees, Dec 16, 2011.

  1. LostInTheTrees macrumors newbie

    Joined:
    Dec 15, 2011
    #1
    I'm new to the Apple dev environment, but have decades of dev experience. Steep learning curve! I am wiring though the Locations example, but have run into t road block. The Locations example has not been updated (AFAIK) for iOS 5, but I seem to be negotiating the differences OK. I keep getting this error:

    uncaught exception 'NSInternalInconsistencyException', reason: '+entityForName: could not locate an NSManagedObjectModel for entity name 'Event''

    I have found several instances of this question and have checked the things suggested. The most detailed was from a suggestion to check context.persistentStoreCoordinator.managedObjectModel.entities to see if the MOC has been created. I get a count of one from this collection and I have one entity defined, Event. So it would seem I have instantiated the MOC.

    The main code I have written is in the AppDelegate. It is listed below. These three functions appear to run correctly. As soon as I exit from didFinishLaunchingWithOptions, the app crashes with the exception. The URL created for the MOM is //localhost/Users/bob/Library/Application%20Support/iPhone%20Simulator/5.0/Applications/9189FD66-7C27-4B2E-9FA6-199361342EDC/Locations.app/Locations.momd/

    I have scattered a few breakpoints around my rootViewController and those are not getting hit, so I am not sure where the code is going after didFinishLaunching... exits. The MOM looks correct and the name is not misspelled AFAIK.

    May main question is what am I doing wrong?
    Second, I follow that URL and I find no Library under /Users/bob. Are there hidden directories? Is this the problem?
    Third, when I exit didFinishLaunching... I am in assembly code. Is there any easy way to get the debugger to stop on the next source code it enters, or do I have to plant breakpoints in the right place?

    Thanks in advance,
    -Bob



    Code:
    #import "AppDelegate.h"
    
    #import "MasterViewController.h"
    #import "RootViewController.h"
    
    @implementation AppDelegate
    
    @synthesize window = _window;
    @synthesize managedObjectContext = __managedObjectContext;
    @synthesize managedObjectModel = __managedObjectModel;
    @synthesize persistentStoreCoordinator = __persistentStoreCoordinator;
    @synthesize navigationController;
    
    - (BOOL)application:(UIApplication *)application 
            didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
        RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
        
        NSManagedObjectContext *context = [self managedObjectContext];
        if (!context) {
            //Handle error
        }
        //Pass managed object context to view controller
        rootViewController.managedObjectContext = context;
        id x = context.persistentStoreCoordinator.managedObjectModel.entities;
        int y = [x count];
        
        UINavigationController *aNavigationController = [[UINavigationController alloc] 
                                                         initWithRootViewController:rootViewController];
        self.navigationController = aNavigationController;
        
        [window addSubview:[navigationController view]];
        [window makeKeyAndVisible];    
    
        return YES;
    }
    - (NSManagedObjectContext *)managedObjectContext
    {
        if (__managedObjectContext != nil)
        {
            return __managedObjectContext;
        }
        
        NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
        if (coordinator != nil)
        {
            __managedObjectContext = [[NSManagedObjectContext alloc] init];
            [__managedObjectContext setPersistentStoreCoordinator:coordinator];
        }
        return __managedObjectContext;
    }
    
    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator
    {
        if (__persistentStoreCoordinator != nil)
        {
            return __persistentStoreCoordinator;
        }
        
        NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Locations.sqlite"];
        
        NSError *error = nil;
        __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
      //if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
      //      configuration:nil URL:storeURL options:nil error:&error])
      //{
            /*
             Replace this implementation with code to handle the error appropriately.
            …
            */
      //}    
      
        return __persistentStoreCoordinator;
    }
    
    - (NSManagedObjectModel *)managedObjectModel
    {
        if (__managedObjectModel != nil)
        {
            return __managedObjectModel;
        }
        NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"Locations" withExtension:@"momd"];
        NSLog(@"scheme:   %@\n", [modelURL scheme]);
        NSLog(@"resource: %@\n", [modelURL resourceSpecifier]);
        __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
        return __managedObjectModel;
    }
     
  2. RonC macrumors regular

    Joined:
    Oct 18, 2007
    Location:
    Chicago-area
    #2
    1. Post the stack backtrace. That will help.
    2. The exception says it can't find the entity information for an entity named "Event". Where is the code that invokes entityForName:? Put a breakpoint before that, and also share that code.

    I've gone through exactly the learning curve you're going through, so I should be able to help some.
     
  3. jonnymo5 macrumors 6502

    Joined:
    Jan 21, 2008
    Location:
    Texas
    #3
    Under the breakpoints tab on the navigation bar in Xcode you can add an exception breakpoint for all exceptions thrown. That should help you narrow it down without having to breakpoint every line of your code. :D
     
  4. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #4
    Thanks.

    I have tried to figure out who is calling entityForName, but I have not been able to. Any suggestions?

    By Stack trace do you mean this:
    Code:
    Thread 1, Queue : (null)
    #0	0x00002958 in -[AppDelegate application:didFinishLaunchingWithOptions:] at /Users/bob/Desktop/Locations/Locations/AppDelegate.m:25
    #1	0x000a09d6 in -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] ()
    #2	0x000a18a6 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] ()
    #3	0x000b0743 in -[UIApplication handleEvent:withNewEvent:] ()
    #4	0x000b11f8 in -[UIApplication sendEvent:] ()
    #5	0x000a4aa9 in _UIApplicationHandleEvent ()
    #6	0x01579fa9 in PurpleEventCallback ()
    #7	0x0174a1c5 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
    #8	0x016af022 in __CFRunLoopDoSource1 ()
    #9	0x016ad90a in __CFRunLoopRun ()
    #10	0x016acdb4 in CFRunLoopRunSpecific ()
    #11	0x016acccb in CFRunLoopRunInMode ()
    #12	0x000a12a7 in -[UIApplication _run] ()
    #13	0x000a2a9b in UIApplicationMain ()
    #14	0x000028c8 in main ()
    -Bob
     
  5. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #5
    Good suggestion. Difficult to find even when you know where to look. Better stack trace below. Could this be because I I have not created a Fetch in the model?

    Here is the code at the point of exception. This is in the MasterViewController
    Code:
    - (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:self.managedObjectContext];
        [fetchRequest setEntity:entity];
    Stack trace:
    Code:
    #0	0x01596cf0 in objc_exception_throw ()
    #1	0x00f4cab7 in +[NSEntityDescription entityForName:inManagedObjectContext:] ()
    #2	0x000045c4 in -[MasterViewController fetchedResultsController] at /Users/bob/Desktop/Locations/Locations/MasterViewController.m:176
    #3	0x00003c82 in -[MasterViewController numberOfSectionsInTableView:] at /Users/bob/Desktop/Locations/Locations/MasterViewController.m:92
    #4	0x0027e0a9 in -[UITableViewRowData(UITableViewRowDataPrivate) _updateNumSections] ()
    #5	0x0027eb69 in -[UITableViewRowData invalidateAllSections] ()
    #6	0x00122a58 in -[UITableView(_UITableViewPrivate) _updateRowData] ()
    #7	0x001229e3 in -[UITableView(_UITableViewPrivate) _ensureRowDataIsLoaded] ()
    #8	0x0012fe47 in -[UITableView numberOfSections] ()
    #9	0x002d1873 in -[UITableViewController viewWillAppear:] ()
    #10	0x00003a6e in -[MasterViewController viewWillAppear:] at /Users/bob/Desktop/Locations/Locations/MasterViewController.m:61
    #11	0x00169fbf in -[UIViewController _setViewAppearState:isAnimating:] ()
    #12	0x0016a21b in -[UIViewController __viewWillAppear:] ()
    #13	0x0017ab71 in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
    #14	0x0017b3df in -[UINavigationController _startDeferredTransitionIfNeeded] ()
    #15	0x00178d9b in -[UINavigationController defaultFirstResponder] ()
    #16	0x0018f441 in -[UIResponder(Internal) _deepestDefaultFirstResponder] ()
    #17	0x0018f45d in -[UIResponder(Internal) _deepestDefaultFirstResponder] ()
    #18	0x0018f4f9 in -[UIResponder(Internal) _promoteDeepestDefaultFirstResponder] ()
    #19	0x000cfd65 in -[UIWindow makeKeyWindow] ()
    #20	0x000cfdac in -[UIWindow makeKeyAndVisible] ()
    #21	0x000a0be6 in -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] ()
    #22	0x000a18a6 in -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] ()
    #23	0x000b0743 in -[UIApplication handleEvent:withNewEvent:] ()
    #24	0x000b11f8 in -[UIApplication sendEvent:] ()
    #25	0x000a4aa9 in _UIApplicationHandleEvent ()
    #26	0x01579fa9 in PurpleEventCallback ()
    #27	0x0174a1c5 in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ ()
    #28	0x016af022 in __CFRunLoopDoSource1 ()
    #29	0x016ad90a in __CFRunLoopRun ()
    #30	0x016acdb4 in CFRunLoopRunSpecific ()
    #31	0x016acccb in CFRunLoopRunInMode ()
    #32	0x000a12a7 in -[UIApplication _run] ()
    #33	0x000a2a9b in UIApplicationMain ()
    #34	0x000028c8 in main at /Users/bob/Desktop/Locations/Locations/main.m:16
    
     
  6. ArtOfWarfare macrumors 604

    ArtOfWarfare

    Joined:
    Nov 26, 2007
    #6
    Users/<Name>/Library is a hidden directory as of Mac OS X 10.7 Lion.

    There's a terminal command you can use to permantly reveal it again, but I forget what it is. I'm sure google can tell you what it is.
     
  7. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #7
    Thanks, I came across that command, but had not tried it yet.

    -Bob
     
  8. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #8
    Now I'm really confused

    I added this code:

    Code:
        id x = context.persistentStoreCoordinator.managedObjectModel.entities;
        for (id y in x) {
            NSLog(@"%@", [y name]);
        }
    
    It prints out the single line
    Code:
    2011-12-16 15:34:33.079 Locations[4259:fb03] Event
    Yet that is exactly what this line is looking for:
    Code:
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:self.managedObjectContext];
    Anyone have an idea what I am screwing up?

    -Bob
     
  9. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #9
    OK almost done

    I know why it is failing. The managedObjectContext property in the MasterViewController object is nil.

    Where should I be setting the MOC for this object? I had already come across this code and tried to put it in the rootViewController viewDidLoad method, but it was not getting called early enough. Is this the best way to do it? It seems clumsy.
    Code:
        if (managedObjectContext == nil) { 
            id a = [UIApplication sharedApplication];
            id b = [a delegate];
            managedObjectContext = [b managedObjectContext]; 
            NSLog(@"After managedObjectContext_: %@",  managedObjectContext);
        }
    Side question: when I use this code:
    Code:
        if (managedObjectContext == nil) { 
            managedObjectContext = [[[UIApplication sharedApplication] delegate] managedObjectContext]; 
            NSLog(@"After managedObjectContext_: %@",  managedObjectContext);        
        }
    I get an error saying that managedObjectContext is not known anywhere as a method. I can't see why there is any difference.

    Another side question: is the MasterViewController code running a super class of my rootViewController or is there something else going on?

    -Bob
     
  10. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #10
    Finally

    I added this code to the viewDidLoad method of MasterViewController.m and that fixed it.
    Code:
        if (managedObjectContext == nil) { 
            id a = [UIApplication sharedApplication];
            id b = [a delegate];
            managedObjectContext = [b managedObjectContext]; 
            NSLog(@"After managedObjectContext_: %@",  managedObjectContext);
        }
    I am still wondering why the more compact syntax is not accepted. And also whether there is better code or a better place for this.

    Thanks for pointing me in the right direction.

    -Bob
     
  11. MattInOz, Dec 16, 2011
    Last edited: Dec 16, 2011

    MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #11
    It seems there is a bug in the current iOS so that managedObjectContext doesn't always get passed to you view. There seem to be a few code blocks to fix it this is the one I use. Which may not be the best way to go. It basically asks the AppDelegate for the MOC if it hasn't been set. (Sorry I'm using ARC so may be missing required memory management).

    in your view controllers .h
    Code:
    @property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;
    in your view controllers .m
    Code:
    @synthesize managedObjectContext = __managedObjectContext;
    
    .....
    Code:
    -(NSManagedObjectContext *)managedObjectContext
    {
        if ( __managedObjectContext == Nil)
        {
             __managedObjectContext = [[[UIApplication sharedApplication] delegate] performSelector:@selector(managedObjectContext)];
        }
        return  __managedObjectContext;
    }
    
    Oh forgot to say its important that if you go this way you always get the managedObjectContext by calling the method (i.e. self.managedObjectContext) if you go to the variable directly you still could get nil.
     
  12. mduser63 macrumors 68040

    mduser63

    Joined:
    Nov 9, 2004
    Location:
    Salt Lake City, UT
    #12
    It's hard to give a detailed explanation without your whole project, but this is probably related to the fact that -[UIApplication delegate] returns an id. In Objective-C id means an instance of any Objective-C class. The compiler will allow you to send any message to (call any method on) and id. However, it does need to know some information about the method being called, so it goes through all the headers in your project trying to find a method with the same name (on any class), and assumes the first one it finds is the right method. If it doesn't find any method in any header in your project with the same name, you get a warning (not an error, unless you've set the compiler up that way).

    Now, all that said, it seems strange that it can't find a method called "managedObjectContext" since that's declared on more than one Cocoa class. However, it may have something to do with the <UIApplicationDelegate> protocol qualifier on the return type of -[UIApplication delegate] method. I'm not really sure how the compiler handles message sends to id<SomeProtocol> types, but it wouldn't surprise me to find out that it only considers classes that declare compliance with SomeProtocol when searching for the correct method signature. Of course, you should also get a warning if your application delegate class doesn't declare compliance with UIApplicationDelegate formal protocol... Again, without being able to see all your code, it's hard to say *exactly* what's going on.

    If you want to read an interesting article about the weaknesses of Objective-C's weak typing system, see here: http://cocoawithlove.com/2011/06/big-weakness-of-objective-c-weak-typing.html . It necessarily includes good information about how all this stuff I've mentioned works. I would add my own commentary by saying that while what he talks about is a real weakness, it's not something that causes frequent problems. I've written Objective-C/Cocoa code for 6 or 7 years and am a full time Mac developer and I've never had the problem he describes come up.
     
  13. LostInTheTrees thread starter macrumors newbie

    Joined:
    Dec 15, 2011
    #13
    Thanks. Raw newbie question here: When you say "your view" do you mean the rootViewController that I put together as part of the example? It's a subclass of UITableViewController and conforms to CLLocationManagerDelegate.

    When I created the project and made the selections as instructed, MasterViewController.h and .m were inserted into my project. When I look at the storyboard, the MVC appears to be a distinct object created by the NavigationController. The MVC object is the one that did not get populated with the MOC until I inserted that code into its viewDidLoad. Am I interpreting that correctly?

    I tried this code in the AppDelegate, but the MVC object was not returned by topViewController so it did not work. Is there another path that would return the right object? My study of the NavigationController did not reveal any solution.
    Code:
    MasterViewController *mvcController = (MasterViewController *)navigationController.topViewController;
    mvcController.managedObjectContext=self.managedObjectContext;
    
    Thanks Matt and mduser63. I'll check out that article.

    -Bob
     
  14. North Bronson macrumors 6502

    Joined:
    Oct 31, 2007
    Location:
    San José
    #14
    My advice is to slow down a little. The Core Data Tutorial for iOS provides a step-by-step guide for building the Locations project. If you follow those steps and cannot make the application work, either start all over and follow each step again, or try a different approach to learning Core Data.

    Try looking at the Core Data Utility Tutorial and follow that example. The tutorial will build a Core Data application without a GUI. That might help you focus on exactly what is happening with the Core Data objects and how they work together.
     
  15. MattInOz macrumors 68030

    MattInOz

    Joined:
    Jan 19, 2006
    Location:
    Sydney
    #15
    Sorry Yes, Newbie here as well. Sorry should have said "Your ViewController". After the view controllers job is the mediate between the Model and the View.

    If you haven't already Buy one of the Big Nerd Ranch Books*. The best thing about them is they walk you through each part of the chain, how they fit together then once you have a good background show you tricks like core data and storyboards that make your life easy. Which makes it much easier to trust those tools. Apples Tutorials tend to jump straight into using the fancy tricks without the background.

    Yes the MasterViewController for some reason is not being passed a reference to the valid ManagedObjectContext so when the NSFetchedResultsController tries to link to the Core Data store it fails.

    *Haven't seen the newest edition of CocoaTouch book, but personally the Cocoa (OSX) book did a much better job of demystifying Core Data than the previous Cocoa Touch book. Still if your serious no reason not to buy both, and a stack of other books to boot.
     
  16. theStarter macrumors newbie

    Joined:
    Jun 29, 2012
    #16
    You guys rock!

    LostInTheTrees, MattInOz, North Bronson and others: You have saved me hours of time. This conversation helped me solve my problem (same issue as LostInTheTrees - working through the Core Data Tutorial). I appreciate the wise counsel of North Bronson to 'slow down a little'...but it is hard to put the brakes on when I am so passionate about my project. Thank you all for your generosity and deep knowledge base.
     

Share This Page