newbie coredata NSManagedObjectModel empty

  • Hi folks

    Teaching myself core data and objective-C at the same time.

    I'm trying to instantiate a NSManagedObjectModel and, while the code
    compiles with no errors (other than test kit errors), I think no
    NSManagedObjects are making their way into the model. ((I hope I'm using the
    right vocabulary here.))

    I'm using the octest // SenTestingKit.framework to exercise custom
    NSManagedObject classes.

    1. I put a breakpoint in the custom NSManagedObject class and, though those
    classes are apparently instantiated and messaged without error, the methods
    are not run as I expect (my breakpoint doesn't get hit).
    2. I tried to take my custom NSManagedObject class out of the picture and
    just use the xcdatamodel directly. Same behavior.

    When I print out the representation of the NSManagedObjectModel it is always
    the same:

    (NSManagedObjectModel) isEditable 0, entities {}, fetch request templates {}

    I haven't been on this list (or using cocoa) for long, so please excuse me
    if I'm about to include an improperly large amount of code and output.

    Jonathan

    code:

    - (void) testOrchestraLocal
    {

    NSArray *bundlesToSearch = [NSArray arrayWithObject:[NSBundle mainBundle]];
    NSManagedObjectModel *model = [[NSManagedObjectModel
    mergedModelFromBundles:bundlesToSearch] retain];
    NSLog(@"the Initial mom model is described as \n%@",model);

    NSPersistentStoreCoordinator *coordinator = [[NSPersistentStoreCoordinator
    alloc] initWithManagedObjectModel:model];
    NSManagedObjectContext *context = [[NSManagedObjectContext alloc] init];
    [context setPersistentStoreCoordinator:coordinator];

    NSLog(@"the Initial mom model is described as \n%@",model);
    NSManagedObject *orch = [NSEntityDescription
    insertNewObjectForEntityForName:@"Orchestra"
    inManagedObjectContext:context];

    NSLog(@"the after orchestra mom model is described as \n%@",model);

    NSString *nameString = [orch valueForKey: @"nameString"];

    NSLog(@"YOU JS!! 1st nameString = %@",nameString);
    NSLog(nameString);

    STAssertEquals(@"New Orchestra", nameString,
    @"Default Orchestra nameString was WRONG, man");

    [orch setValue:@"THE NEW NAME"
    forKey:@"nameString"];

    NSString *newNameString = [orch valueForKey: @"nameString"];

    STAssertEquals(@"THE NEW NAME" , newNameString,
    @"Default Orchestra nameString was WRONG, man");

    NSLog(@"YOU JS!! 2nd nameString = %@",newNameString);
    NSLog(newNameString);

    [orch release];
    [context release];
    [model release];
    }

    ERRORS:
    /Volumes/Docs/Users/jonathan/svnCheckouts/OrchestrationTool/trunk/exerciseModel.m:151:
    error: -[exerciseModel testOrchestra] : '2' should be equal to '0': Default
    Orchestra a440Int should have been changed to 2, but was 0 instead!
    /Volumes/Docs/Users/jonathan/svnCheckouts/OrchestrationTool/trunk/exerciseModel.m:77:
    error: -[exerciseModel testOrchestraLocal] : '<000ae054 >' should be equal
    to '<00000000 >': Default Orchestra nameString was WRONG, man
    /Volumes/Docs/Users/jonathan/svnCheckouts/OrchestrationTool/trunk/exerciseModel.m:96:
    error: -[exerciseModel testOrchestraLocal] : '<000ae060 >' should be equal
    to '<00000000 >': Default Orchestra nameString was WRONG, man

    gdb Output:
    Test Suite
    '/Volumes/Docs/Users/jonathan/build/Debug/testCases.octest(Tests)' started
    at 2005-10-12 20:22:02 -0400
    Test Suite 'exerciseModel' started at 2005-10-12 20:22:02 -0400
    Current language: auto; currently objective-c
    2005-10-12 20:22:16.710 otest[7266] the Initial mom model is described as
    (NSManagedObjectModel) isEditable 0, entities {}, fetch request templates {}
    2005-10-12 20:22:16.710 otest[7266] the after orchestra mom model is
    described as
    (NSManagedObjectModel) isEditable 0, entities {}, fetch request templates {}
    2005-10-12 20:22:20.620 otest[7266] YOU JS!! 1st nameString = (null)
    /Volumes/Docs/Users/jonathan/svnCheckouts/OrchestrationTool/trunk/exerciseModel.m:77:
    error: -[exerciseModel testOrchestraLocal] : '<000ae054 >' should be equal
    to '<00000000 >': Default Orchestra nameString was WRONG, man
    /Volumes/Docs/Users/jonathan/svnCheckouts/OrchestrationTool/trunk/exerciseModel.m:96:
    error: -[exerciseModel testOrchestraLocal] : '<000ae060 >' should be equal
    to '<00000000 >': Default Orchestra nameString was WRONG, man
    2005-10-12 20:22:22.790 otest[7266] YOU JS!! 2nd nameString = (null)
    Test Case '-[exerciseModel testOrchestraLocal]' failed (20.494 seconds).

    --
    The extent to which an individual can resist being blindly led by tradition
    is a good measure of his vitality. - Harry Partch

    There is a computer disease that anybody who works with computers knows
    about. It's a very serious disease and it interferes completely with the
    work. The trouble with computers is that you 'play' with them! - Richard P.
    Feynman
  • > From Matthew Firlik at apple (who mentioned in a subsequent email that
    he meant to publish this to the list)

    On Oct 12, 2005, at 5:31 PM, Jonathan Saggau wrote:

    When I print out the representation of the NSManagedObjectModel it is always
    the same:

    (NSManagedObjectModel) isEditable 0, entities {}, fetch request templates {}

    > From the log it is clear you have a model with no entities in it ...
    which means the API (mergedModelFromBundles:) is not finding any
    models to merge together.  You can validate this further by putting in
    this simple code in your application initialization code:

    = = = = =

        // print out all of the models
        NSLog( @"Models in bundle '%@': %@",
            [[NSBundle mainBundle] resourcePath],
            [[NSBundle mainBundle] pathsForResourcesOfType:@"mom"
    inDirectory:nil] );
        }

    = = = = =

    This is what Core Data is doing "under the hood":  we look for all
    files with the ".mom" extension in the bundles and merge them in.  I'm
    guessing this code will also return an empty array when you run it,
    which means Core Data can't find any models to merge in.  If that is
    the case, here's what I'd try to debug it:

    = = = = =

    Ensure the model is included in your target
    If the model isn't included in the target, it won't be processed (and
    thus not installed, and then not found.)  In the "Groups and Files"
    view of Xcode, find the target the model is supposed to be in, and
    expand it.  Then expand the "Compile Sources" phase.  Your model
    should be listed there.  If it isn't, drag the model icon from it's
    main location in the "Groups and Files" view to that phase, to add it.

    Ensure the model is being compiled
    If the model is in the target and the rule is set up correctly, you
    should be able to see it being processed in the build log.  Clean and
    rebuild your project, and then consult the Xcode "Build Results" log.
    There should be an entry in the build steps for "Compiling
    <YOUR_MODEL_NAME>.xcdatamodel]"  If there isn't an entry, then it
    might be you are missing a build rules for the models ...

    Ensure you have a build rule
    Xcode processes model files like sources:  we validate it and compile
    it down into a runtime format.  This is done with a special model
    compiler, which Xcode normally associates with that file type.
    Double-click on your target icon, and from the inspector that comes up
    select the "Rules" tab.  Ensure there is a "Data Model Compiler" rule,
    and that it is set up to process "Data model files" using the "Data
    Model Compiler."  If it isn't listed, use the plus button at the
    bottom of the window to add one.

    Ensure the runtime model is in the right place
    The Core Data code expects two things from the runtime models -- that
    they end in ".mom" (which is done by the model compiler) and they are
    stored in the "Resources" of the deployed bundle.  If everything looks
    correct from Xcode, then find your built product, show the package
    contents, and look in the "Resources" folder.  You should find a file
    called <YOUR_MODEL_NAME>.mom there.  If not, then that's bug-worthy as
    well.

    Load the model manually
    If you DO find an installed model, then it may be something is wrong
    with it (causing it not to be loaded.)  Instead of using the
    mergedModelFromBundles: method, you can also load models directly via
    a URL:

        NSManagedObjectModel *model = [[NSManagedObjectModel alloc]
    initWithContentsOfURL:
        [NSURL fileURLWithPath:@"/path/to/your/model.mom"]];

    So you can try this if you find the model manually, to see if you can
    load it that way as well.

    = = = = =

    Hope that helps.

    - matthew
    --
    The extent to which an individual can resist being blindly led by
    tradition is a good measure of his vitality.  - Harry Partch

    There is a computer disease that anybody who works with computers
    knows about. It's a very serious disease and it interferes completely
    with the work. The trouble with computers is that you 'play' with
    them! - Richard P. Feynman

    Few people are capable of expressing with equanimity opinions which
    differ from the prejudices of their social environment.  Most people
    are not even capable of forming such opinions.  - Einstein
  • More interesting info from Matthew on how to load NSManagedObjectModels::

    On Oct 13, 2005, at 3:13 PM, Jonathan Saggau wrote:

    > AHA!  Thanks Matthew!
    >
    > Here's what's happened:
    > I'm using the /Developer/Tools/otest executable as the target for
    > my test bundle testCases.octest, so the resourcepath was /Developer/
    > Tools.  The .mom file is in the bundle!

    (Matthew)

    Ah ... I didn't realize you were using a testing tool.  Yes, the
    [NSBundle mainBundle] API will return the bundle for the executable,
    which is why it returned "/Developer/Tools/".

    > 2.  Is there a smarter target to use besides /Developer/Tools/otest
    > (or should I put the otest executable in the testCases.octest or
    > something)?  I would rather not hard-code the
    > initWithContentsOfURL: path for portability sake.  (I have a buddy
    > who wants to play with this tool I'm working on).

    I would agree, hard-coding the URL to the model is less-than-ideal.
    However, there is some degree of 'static definition' that must exist
    between your test cases and the product being tested.  Rather, since
    your tests are testing a specific collection of functionality (for
    example, the code in something like "BusinessLogic.framework"), you
    may be able to use that bit of information with a little glue code to
    make it work.

    In fact ... you may have, already.  It strikes me that you are trying
    to test content which is in a bundle -- but is the model the only
    thing in the bundle?  Is there no source code either?  You'd have to
    have the bundle loaded in at some point, if you have source code,
    otherwise it won't be able to execute.  If you've already linked in
    the framework or loaded your bundle into your project, you should be
    passing in something OTHER than "mainBundle" for the managed object
    model API, since we KNOW the model isn't there.  For example:

        NSManagedObjectModel *model = [NSManagedObjectModel
    mergedModelFromBundles:
            [NSBundle allBundles]]

    would load the models from all of the NON-FRAMEWORK bundles.  (You'd
    want to use this if your application was using a series of plugins or
    the like.)  You can also do:

        NSManagedObjectModel *model = [NSManagedObjectModel
    mergedModelFromBundles:
            [NSBundle allFrameworks]]

    and create a model from all of the framework bundles.  You could even
    be much more specific, ala:

        NSBundle *myBundle = [NSBundle bundleWithIdentifier:
    @"my.bundle.identifier"];
        NSManagedObjectModel *model = [NSManagedObjectModel
    mergedModelFromBundles:
            [NSArray arrayWithObject: myBundle]];

    to load JUST the models from JUST your bundle.  (Note the identifier
    you use is the CFBundleIdentifier, not the name of the bundle
    itself.  You can set the bundle identifier by using the "Properties"
    tab of the inspector for your bundle's target, in Xcode.)  But of
    course, these are only ways to get models from bundle you already
    have LOADED, which may not be your case.

    However, loading bundles manually is rather easy.  You can imagine a
    setup where you have your test setup use a command-line variable or
    user default to define the bundles it should automatically load on
    startup.
previous month october 2005 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
Go to today