NSArrayController initialization
Asked Answered
M

3

8

I am having trouble getting an core-data backed NSArrayController to work properly in my code. Below is my code:

pageArrayController = [[NSArrayController alloc] initWithContent:nil];
    [pageArrayController setManagedObjectContext:[self managedObjectContext]];
    [pageArrayController setEntityName:@"Page"];
    [pageArrayController setAvoidsEmptySelection:YES];
    [pageArrayController setPreservesSelection:YES];
    [pageArrayController setSelectsInsertedObjects:YES];
    [pageArrayController setClearsFilterPredicateOnInsertion:YES];
    [pageArrayController setEditable:YES];
    [pageArrayController setAutomaticallyPreparesContent:YES];
    [pageArrayController setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"index" ascending:YES]]];
    BOOL result = [pageArrayController setSelectionIndex:0];

When I attempt to call setSelectionIndex:, it returns YES, indicating that the selection has been successfully changed. However, any subsequent getSelectionIndex calls to the pageArrayController object returns NSNotFound.

What I don't understand is that if I put the NSArrayController into a NIB, and allow the NIB file to perform the initialization (with all of the same attributes in Interface Builder), the NSArrayController works correctly.

Why is there a difference in behavior? Does the NIB file initialize these types of objects in a special way? Is my initialization of the NSArrayController incorrect?

Any help is appreciated. Thanks.

Meri answered 7/12, 2009 at 15:46 Comment(2)
There is no such thing as a -getSelectionIndex method. Did you write such a method yourself, or actually calling something different?Alexia
I meant -selectionIndex.Meri
M
16

Yes, nibs do initialize objects in a special way and sometimes it can be hard to figure out how to replicate that. I struggled with this too and finally found the answer in Apple's Core Data Programming Guide >> Core Data and Cooca Bindings >> Automatically Prepares Content Flag (thanks to Dave Fernandes on the Cocoa Dev list). The answer is that if you initialize an arraycontroller with nil content, you need to perform a fetch as well.

BOOL result;
NSArrayController *pageArrayController = [[NSArrayController alloc] initWithContent:nil];
[pageArrayController setManagedObjectContext:[self managedObjectContext]];
[pageArrayController setEntityName:@"Page"];
NSError *error;
if ([pageArrayController fetchWithRequest:nil merge:YES error:&error] == NO) 
     result = NO;
else
{
     //do all that other pageArrayController configuration stuff
     result = [pageArrayController setSelectionIndex:0];
}

BTW, [NSSortDescriptor sortDescriptorWithKey:@"index" ascending:YES]] raises a warning.

Marlie answered 7/12, 2009 at 20:25 Comment(5)
Also, your use of [self managedObjectContext] implicates that you have added your pageArrayController methods to the appDelegate. This is not considered good practice. You really should look into creating a separate page controller object (and model and view objects, as necessary to implement the MVC pattern) that will take care of the whole page functionality of your application. The page controller or page model objects may call [[NSApp delegate] managedObjectContext] when necessary.Marlie
Thanks for this solution, it works perfectly. My app structure is much nicer now that I can create these array controllers in code rather than relying on nibs.Meri
You my friend, are a legend! I spent days trying to figure out why my array controller was not updating as new data came into my Core Data store from iCloud. Now it works perfectly. Thank you.Gallic
And then, how would you connect an NSTableView to this programmatically-created NSArrayController ? In the code or can you use Interface builder ?Boozer
You need code to establish the binding, but the tableview can be created in IB. Just make sure to declare an IBOutlet to the tableview and then do something like this: [self.theTableView.column bind:NSValueBinding toObject:theArrayController withKeyPath:[NSString stringWithFormat:@"arrangedObjects.%@", anAttributeName] options:theValueOptions];Marlie
F
0

As far as why there may be a difference in behavior:

  1. Nib files store serialized objects using NSCoder.
  2. You are probably using binding on the IB side of things, where in your code you are setting the managed object context directly using a set method.

Maybe you could try something like the following in your code:

[pageArrayController bind:@"managedObjectContext"
                 toObject:self
              withKeyPath:@"managedObjectContext"
                  options:nil];

I don't have Xcode near by otherwise I would try somethings. Hopefully this gives you some clues to get you going in the right direction.

Flowerpot answered 7/12, 2009 at 16:13 Comment(0)
M
0

From where are you creating/configuring your array controller? The Core Data stack may not be ready yet, therefore your call to [self managedObjectContext] may be returning nil.

Also, why are you creating it programmatically if you can do it just fine with Interface Builder? The tool is there and works well (and eliminates many possible coding errors), so unless you have a good reason not to use it, you're not doing yourself any favors.

Mond answered 7/12, 2009 at 20:24 Comment(1)
Well in my case i create NSArrayController in code as when using IB, binded data in NSArrayController aren't loaded yet in awakeFromNib method. Do you know how to resolve issue in IB ?Thermistor

© 2022 - 2024 — McMap. All rights reserved.