NSKeyedArchiver fails with CLLocationCoordinate2D structs. What for?

I do not understand why I can archive CGPoint structures, but not CLLocationCoordinate2D structs. What is the difference with the archiver?

The platform is iOS. I am running in the simulator and have not tried it 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 failure in the second archiveRootObject , and this message prints to the console:

 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs' 
+6
source share
3 answers

Ok Tom, are you ready for some geek? I am the β€œsenior” guy in this world of young shooters. However, I remember a few things about C, and I'm just a geek at heart.

In any case, there is a slight difference between this:

 typedef struct { double d1, d2; } Foo1; 

and this:

 typedef struct Foo2 { double d1, d2; } Foo2; 

The first is a type alias for an anonymous structure. The second is an alias of type struct Foo2 .

Now the documentation for @encode states that the following:

 typedef struct example { id anObject; char *aString; int anInt; } Example; 

will result in { example=@ *i} for @encode(example) or @encode(example) . So this means that @encode uses the actual structure tag. In the case of a typedef that creates an alias for the anonymous structure, it looks like this: @encode always returns ? ''

Check this:

 NSLog(@"Foo1: %s", @encode(Foo1)); NSLog(@"Foo2: %s", @encode(Foo2)); 

In any case, can you guess how CLLocationCoordinate2D is determined? Yeah. You guessed it.

 typedef struct { CLLocationDegrees latitude; CLLocationDegrees longitude; } CLLocationCoordinate2D; 

I think you should submit a bug report. Either @encode broken because it does not use alias typedefs for anonymous structures, or CLLocationCoordinate2D must be fully typed, so it is not an anonymous structure.

+18
source

To get around this limitation until the error is fixed, just add the coordinates and restore:

 - (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 }; ... 
+3
source

This is because @encode clamps CLLocationCoordinate2D

NSLog(@"coords %@; type: %s", coords, @encode(CLLocationCoordinate2D)); gives coords ( "<00000000 00405e40 00000000 00804440>" ); type: {?=dd} coords ( "<00000000 00405e40 00000000 00804440>" ); type: {?=dd}

0
source

Source: https://habr.com/ru/post/924684/


All Articles