I don't understand why I can archive CGPoint
structs but not CLLocationCoordinate2D
structs. What's the difference to the archiver?
Platform is iOS. I'm running in the simulator and haven't tried on the device.
// why does this work:
NSMutableArray *points = [[[NSMutableArray alloc] init] autorelease];
CGPoint p = CGPointMake(10, 11);
[points addObject:[NSValue valueWithBytes: &p objCType: @encode(CGPoint)]];
[NSKeyedArchiver archiveRootObject:points toFile: @"/Volumes/Macintosh HD 2/points.bin" ];
// and this doesnt work:
NSMutableArray *coords = [[[NSMutableArray alloc] init] autorelease];
CLLocationCoordinate2D c = CLLocationCoordinate2DMake(121, 41);
[coords addObject:[NSValue valueWithBytes: &c objCType: @encode(CLLocationCoordinate2D)]];
[NSKeyedArchiver archiveRootObject:coords toFile: @"/Volumes/Macintosh HD 2/coords.bin" ];
I get a crash on the 2nd archiveRootObject
and this message is printed to the console:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs'
OK, Tom, are you ready for some geek-ness? I'm an "older" guy in this world of young whippersnappers. However, I remember a few things about C, and I'm just a geek at heart.
Anyway, there is a subtle difference between this:
typedef struct { double d1, d2; } Foo1;
and this:
typedef struct Foo2 { double d1, d2; } Foo2;
The first is a type alias to an anonymous structure. The second is a type alias to struct Foo2
.
Now, the documentation for @encode
says that the following:
typedef struct example {
id anObject;
char *aString;
int anInt;
} Example;
will result in {example=@*i}
for both @encode(example)
or @encode(Example)
. So, this implies that @encode
is using the actual struct tag. In the case of a typedef that creates an alias to an anonymous struct, it looks like @encode
always returns ?
'
Check this out:
NSLog(@"Foo1: %s", @encode(Foo1));
NSLog(@"Foo2: %s", @encode(Foo2));
Anyway, can you guess how CLLocationCoordinate2D is defined? Yep. You guessed it.
typedef struct {
CLLocationDegrees latitude;
CLLocationDegrees longitude;
} CLLocationCoordinate2D;
I think you should file a bug report on this. Either @encode
is broken because it does not use alias typedefs to anonymous structs, or CLLocationCoordinate2D needs to be fully typed so it is not an anonymous struct.
To get around this limitation until the bug is fixed, simply break down the coordinates and reconstruct:
- (void)encodeWithCoder:(NSCoder *)coder
{
NSNumber *latitude = [NSNumber numberWithDouble:self.coordinate.latitude];
NSNumber *longitude = [NSNumber numberWithDouble:self.coordinate.longitude];
[coder encodeObject:latitude forKey:@"latitude"];
[coder encodeObject:longitude forKey:@"longitude"];
...
- (id)initWithCoder:(NSCoder *)decoder
{
CLLocationDegrees latitude = (CLLocationDegrees)[(NSNumber*)[decoder decodeObjectForKey:@"latitude"] doubleValue];
CLLocationDegrees longitude = (CLLocationDegrees)[(NSNumber*)[decoder decodeObjectForKey:@"longitude"] doubleValue];
CLLocationCoordinate2D coordinate = (CLLocationCoordinate2D) { latitude, longitude };
...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With