views:

95

answers:

3

I have to store a custom class object to Coredata. The problem is my custom class contains structs,enum etc.I tried following method.

-(void)encodeWithCoder:(NSCoder *)encoder .

But am getting this error

[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs'

What is the best practice to store this object to Coredata. Please help me.

+1  A: 

With a struct, I think, it would be best to create a function that can encode and decode the struct, like any Objective-C object.

With enums, I am not so sure. Enums are just numbers associated with a name, so just enode and decode them as a numbers.

kuroutadori
+2  A: 

You can wrap the struct in a NSData, ie

To encode with archiver

[coder encodeObject:[NSData dataWithBytes:&my_struct length:sizeof(my_struct)] 
             forKey:@"my_struct"];

and to decode with archiver

NSData *data = [coder decodeObjectForKey:@"my_struct"];
[data getBytes:&my_struct length:sizeof(my_struct)];
epatel
using dataWithBytes:length: is not portable between different endian or 32/64 bit platforms. Using this will cause yore data to be stuck to the given device and users will not be able to upgrade to different platforms or transfer/open the file on a different platform than the one it was created on.
Brent Priddy
@Brent Sure...but the question is about iPhone and I think this should work fine for a few years...and if Apple will change the hardware i believe (a) they will have a period using an emulator to bring over as much software as possible (b) the program will have to be recompiled and can be fixed when then (if needed)...and it is only a problem for "data" created/stored on one type of hardware, which the is transferred to a new different architecture...
epatel
@epatel I have customers on PPC and Intel transferring CoreData backup files to/from an iPhone. This recommendation would have caused me headache if I listened to it. You can build ARM 6/7 code for the iPhone, tis not a stretch to think of 32/64 bit fat binaries in the future. This was a "be careful" comment, and I recommend the NSCoder method mentioned below it is safe forever not just in the short term "for a few years".
Brent Priddy
@Brent I hear you. Still, the question was stated as an iPhone specific one and as a developer on multiple platforms I do not see this as a major problem. Why invest development+testing today if you are not sure it will be used. Projects I'm working on use old saved data as defacto formats, making appropriate aligning and swapping when necessary, and we have tools for that. As a consultant my customer do not want to pay for "future" things that "might" be needed. I believe this is also one of the corner stones of agile development.
epatel
@Brent...and, today I usually argue to add a format version field/entry in all saved files to be able to identify different formats between releases. For plist this is very easy, just set a string for some version key. With this one will always have the possibility to do any appropriate conversion...when needed.
epatel
@epatel That is a useful point for the version field. @Sijo another useful point: Make sure that your structs only have primitive types (no stl classes) also make sure that your structs do not have pointers as well... Oh and make sure that sizeof(my_struct) has not changed (sizeof bool can change per compiler and compiler settings, and sizeof enum not set in stone). Make sure you don't reorder your struct or any struct that your struct contains... I guess using this method makes you think of caveats. I guess I am suggesting this because been there done that and don't want to do it again.
Brent Priddy
+2  A: 

You should have a custom implementation of the NSCoding protocol in your custom class. In your own implementations of -[initWithCoder:] and -[encodeWithCoder:], you can then encode/decode the struct objects in any way you please.

On way to do this would be to call [coder encodeObject:[NSValue valueWithBytes:&yourStructVariable objCType:@encode(struct YourStructName)] forKey:@"someKey"]; in -[encodeWithCoder:] and do the equivalent decoding in -[initWithCoder:].

You can then just store the class objects as transformable in Core Data.

mrueg