views:

30

answers:

1

Dear all

I'm starting to feel rather stupid - I've browsed the site and found a few things that come close to my problem but just can't figure it out (help M. Zarra, after reading your book I felt pretty good about Core Data but now I'm at my wits' end!). Despite the expert's advice I've chosen to store an NSMutableArray as a transformable attribute in my core data entity. The array itself is populated with custom objects and has the required encodeWithCoder: and initWithCoder: methods. I've added NSLogs in there to see when they fire.

Now, running the first time, populating everything, etc. it's fine and I do save everything on exit (I can see in the xml file that the stuff got coded in.)

However, when restarting, retrieving the NSManagedObject and then trying to access the transformable attribute I get nothing back - despite the log statements indicating that the initWithCoder: ran successfully. It's as though the decoding is done as part of fetching the NSManagedObject but the attribute itself is not populated (I've tried everything including setReturnsObjectsAsFaults:No). Printing the object description shows 'priceData - "(...not nil...)" so I really don't know why it then doesn't allow access/returns nothing.

What I am trying to do is get the mutableArray, check if it contains an element and if it does, replace it with something else. I started this morning and thought this would be quite simple but 7 hours later I'm still nowhere. The

Any ideas at all? I would really appreciate any help/hints/advice in this matter.

[Secondary question - why is it -apparently- foolish to put data in an array in core data? I'm dealing with long timeseries for many, many individual cases and the option of extruding each data point into an entity seems as though it would create a gigantic table of timeseries data points on which I presume fetch performance would just degrade very quickly. Am I wrong?]

The code is given below:

NSManagedObjectContext *managedObjectContext = [[NSApp delegate] managedObjectContext];
//1. Retrieve the NSManagedObject with the price history from the MOC
NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
[request setIncludesSubentities:YES];
[request setIncludesPendingChanges:YES];
[request setIncludesPropertyValues:YES];
[request setReturnsObjectsAsFaults:NO];
NSEntityDescription *entity =
[NSEntityDescription entityForName:@"stockPriceHistory" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSPredicate *predicate =
[NSPredicate predicateWithFormat:@"stock == %@", [[self selectedObjects]objectAtIndex:0]];
[request setPredicate:predicate];
NSError *error;
NSArray *array = [ managedObjectContext executeFetchRequest:request error:&error];

NSManagedObject *test = [array objectAtIndex:0];

NSLog([test description]);
NSLog(@"%@",[[test priceData] description]);

.. which gives the following log output (the first lines are the logs showing the timestamps on the objects in the array got decoded again):

2010-08-29 18:48:54.245 Project X[23047:a0f] 2010-08-27 13:00:00 +0200

2010-08-29 18:48:54.246 Project X[23047:a0f] 2010-08-26 13:00:00 +0200

2010-08-29 18:48:54.250 Project X[23047:a0f] 2010-08-25 13:00:00 +0200

2010-08-29 18:48:54.251 Project X[23047:a0f] 2010-08-24 13:00:00 +0200

2010-08-29 18:48:54.252 Project X[23047:a0f] 2010-08-23 13:00:00 +0200

2010-08-29 18:48:54.253 Project X[23047:a0f] 2010-08-20 13:00:00 +0200

2010-08-29 18:48:54.253 Project X[23047:a0f] 2010-08-19 13:00:00 +0200

2010-08-29 18:48:54.255 Project X[23047:a0f] 2010-08-18 13:00:00 +0200

2010-08-29 18:48:54.255 Project X[23047:a0f] 2010-08-17 13:00:00 +0200

2010-08-29 18:48:54.256 Project X[23047:a0f] 2010-08-16 13:00:00 +0200

2010-08-29 18:48:54.256 Project X[23047:a0f] 2010-08-13 13:00:00 +0200

2010-08-29 18:48:54.257 Project X[23047:a0f] 2010-08-12 13:00:00 +0200

2010-08-29 18:48:54.258 Project X[23047:a0f] (entity: stockPriceHistory; id: 0x10043d950 ; data: { dataPointCount = 0; priceData = "(...not nil..)"; stock = "0x100445040 "; })

2010-08-29 18:48:54.260 Project X[23047:a0f] ( ) (gdb)

A: 

Did you override NSManagedObject for this class? If so, did you override the accessors for the array? Is its awakeFromFetch method being invoked? Where is the initWithCoder call being made? Probably should be in awakeFromFetch. You could have one persistent attribute 'codedArray' and another non-persistent attribute 'array'. In awakeFromFetch, read the 'codedArray' attribute, decode it, and set the 'array' property which is what the rest of the code will read.

codedArray = [self valueForKey:@"codedArray"];
// decode array...
[self setPrimitiveValue:decodedArray forKey:@"array"]; 

Why are you putting just an array in Core Data? Um, yeah, does seem odd. If you're using a coder you could just write to a flat file. Since you're emitting each object as its own row, you lose the benefits of a SQL DB; you have to read the entire array into memory before doing searches on it.

Graham Perks
Thanks for your reply. I think I sort of follow. The objects are: priceHistory:NSManagedObject, which contains the transformable attribute (which itself consists of other objects that get encoded as described above). I am not doing any en/decoding on the NSMutableArray itself as I let Core Data do that. So I'm not sure what benefit your method would have? Effectively one would have two properties but I think one will do - as in my code, which works and saves the things correctly but for some reason doesn't get them back out from Core Data.
NSSunrider
Ah, sorry, my Core Data code is 10.4 compatible which didn't do all the encoding for you. Hopefully nowadays you don't need to pair of attributes.Are you overriding the KVC attribute accessors for priceHistory?
Graham Perks
I did try overriding (changing the standard xcode 4 template code from id to NSMutableArray) and I tried without overriding anything - same result.
NSSunrider