Reputation: 120
I would like to use an NSArrayController to provide data to an NSTableView. The problem I am facing is that I do not want to pre-load all my data into an array and then use the array controllers setContent:
method. My data model is a large existing code base that manages millions of records. It contains methods to efficiently return a set of data rows.
Following an example I found on limiting the number of objects in an NSArrayController, I tried subclassing NSArrayController and overriding the arrangedObjects:
method to return an array proxy class I wrote. The array proxy class provided count:
and objectAtIndex:
methods. The object returned by objectAtIndex:
is an NSDictionary. When I tried returning my array proxy from the arrangedObjects:
method both count:
and objectAtIndex:
get called, but I also get an unrecognized selector error on my array proxy class for _valueForKeyPath:ofObjectAtIndex:
. This looked like a private method, so I did not continue down this path.
I also thought of returning a smaller array of data from arrangedObjects:
, but could not figure out how I would determine which rows the NSTableView was trying to display.
Is a datasource the "correct" way to interface with my existing data model or is there some way to make an NSArrayController work?
Upvotes: 4
Views: 963
Reputation: 4232
NSArrayController already works, with proxies and indexes and lazy-loading and the whole shabang. Have you tried just using it as-is? If afterwards you feel the need to micro-manage the data-loading, use NSFetchRequest. Subclass NSArrayController and add an initializer along these lines:
+ (id)arrayControllerWithEntityName: (NSString *)entityName error:(NSError **)error
{
id newInstance = [[[self alloc] initWithContent:nil] autorelease];
[newInstance setManagedObjectContext:[[NSApp delegate] managedObjectContext]];
[newInstance setEntityName:entityName];
[newInstance setAutomaticallyPreparesContent:YES];
[newInstance setSelectsInsertedObjects:YES];
[newInstance setAvoidsEmptySelection:YES];
[newInstance setAlwaysUsesMultipleValuesMarker:YES];
NSFetchRequest *dontGobbleRequest = [[[NSFetchRequest alloc] init] autorelease];
//configure the request with fetchLimit and fetchOffset an' all that
NSError *err;
if ([newInstance fetchWithRequest:dontGobbleRequest merge:YES error:&err] == NO) {
//better check docs whether merge:YES is what you want
if(*error && err) {
*error = err;
}
return nil;
}
return newInstance;
}
You'll have to do some research into the various possibilities and configurations, but you get the picture.
Upvotes: 2