How do you populate a NSArrayController with CoreD

2019-06-07 02:32发布

问题:

After several hours/days of searching and diving into example projects I've concluded that I need to just ask. If I bind the assetsView (IKImageBrowserView) directly to an IB instance of NSArrayController everything works just fine.

- (void) awakeFromNib
{
    library = [[NSArrayController alloc] init];
    [library setManagedObjectContext:[[NSApp delegate] managedObjectContext]];
    [library setEntityName:@"Asset"];       

    NSLog(@"%@", [library arrangedObjects]);
    NSLog(@"%@", [library content]);

    [assetsView setDataSource:library];
    [assetsView reloadData];
}

Both NSLogs are empty. I know I'm missing something... I just don't know what. The goal is to eventually allow multiple instances of this view's "library" filtered programmatically with a predicate. For now I'm just trying to have it display all of the rows for the "Asset" entity.

Addition: If I create the NSArrayController in IB and then try to log [library arrangedObjects] or manually set the data source for assetsView I get the same empty results. Like I said earlier, if I bind library.arrangedObjects to assetsView.content (IKImageBrowserView) in IB - with same managed object context and same entity name set by IB - everything works as expected.

- (void) awakeFromNib
{
//  library = [[NSArrayController alloc] init];
//  [library setManagedObjectContext:[[NSApp delegate] managedObjectContext]];
//  [library setEntityName:@"Asset"];       

    NSLog(@"%@", [library arrangedObjects]);
    NSLog(@"%@", [library content]);

    [assetsView setDataSource:library];
    [assetsView reloadData];
}

回答1:

It looks like the problem is that you have not actually told the NSArrayController to fetch anything. NSArrayControllers are empty until you add objects either through bindings or manually.

After setting up library try to call its fetch method:

[library fetch:self];

Also, you probably know this already but it is possible to set bindings in code with the following method:

- (void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options


回答2:

I was running into a similar situation where the (IKImageBrowserView) was not initializing even though the ArrayController would ultimately sync up with the NSManagedObjectContext.

Ultimately found this passage in the core data programming guide

https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CoreData/Articles/cdBindings.html#//apple_ref/doc/uid/TP40004194-SW3

if the "automatically prepares content" flag (see, for example, setAutomaticallyPreparesContent:) is set for a controller, the controller's initial content is fetched from its managed object context using the controller's current fetch predicate. It is important to note that the controller's fetch is executed as a delayed operation performed after its managed object context is set (by nib loading)—this therefore happens after awakeFromNib and windowControllerDidLoadNib:. This can create a problem if you want to perform an operation with the contents of an object controller in either of these methods, since the controller's content is nil. You can work around this by executing the fetch "manually" with fetchWithRequest:merge:error:.

- (void)windowControllerDidLoadNib:(NSWindowController *) windowController
{
[super windowControllerDidLoadNib:windowController];

NSError *error = nil;
BOOL ok = [arrayController fetchWithRequest:nil merge:NO error:&error];
// ...


回答3:

Can also be added in awakeFromNib if subclassing the NSArrayCotroller or via your view controller

-(void)awakeFromNib
{
    [self fetchWithRequest:nil merge:NO error:nil];

    ...
}