Encoding a CLLocationcoordinate2D
Asked Answered
C

4

10

I am trying to encode annotations that are on a map, but I read that I am not able to encode CLLocationcoordinate2D variables. Does anyone know how I can solve this? Here is some code.

This is where I drop the pins:

- (void)press:(UILongPressGestureRecognizer *)recognizer {
    CGPoint touchPoint = [recognizer locationInView:_worldView];
    CLLocationCoordinate2D touchMapCoordinate = [_worldView convertPoint:touchPoint toCoordinateFromView:_worldView];

    geocoder = [[CLGeocoder alloc]init];
    CLLocation *location = [[CLLocation alloc]initWithCoordinate:touchMapCoordinate
                                                    altitude:CLLocationDistanceMax
                                          horizontalAccuracy:kCLLocationAccuracyBest
                                            verticalAccuracy:kCLLocationAccuracyBest
                                                   timestamp:[NSDate date]];
    [geocoder reverseGeocodeLocation:location
               completionHandler:^(NSArray *placemarks, NSError *error) {
                   //NSLog(@"reverseGeocoder:completionHandler: called");
                   if (error) {
                       //NSLog(@"Geocoder failed with error: %@", error);
                   } else {
                       CLPlacemark *place = [placemarks objectAtIndex:0];
                       geocodedAddress = [NSString stringWithFormat:@"%@ %@, %@ %@", [place subThoroughfare], [place thoroughfare], [place locality], [place administrativeArea]];
                       if (UIGestureRecognizerStateBegan == [recognizer state]) {
                           value = [number intValue];
                           number = [NSNumber numberWithInt:value + 1];
                           _addressPin = [[MapPoint alloc]initWithAddress:geocodedAddress coordinate:touchMapCoordinate
                                                                   title:geocodedAddress identifier:number];
                           NSLog(@"The identifier is %@", number);
                           [[Data singleton].annotations addObject:_addressPin];
                           [_worldView addAnnotation:_addressPin];
                           NSLog(@"The number of pins in the annotation array is: %u",[Data singleton].annotations.count);
                       }
                   }
               }];
}

Here is my class that conforms to the MKAnnotation protcol:

#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>

@interface MapPoint : NSObject <MKAnnotation, NSCoding>
{
}

- (id)initWithAddress:(NSString*)address
    coordinate:(CLLocationCoordinate2D)coordinate
         title:(NSString *)t
       identifier:(NSNumber *)ident;


//This is a required property from MKAnnotation
@property (nonatomic, readonly) CLLocationCoordinate2D coordinate;

//This is an optional property from MKAnnotataion
@property (nonatomic, copy) NSString *title;
@property (nonatomic, readonly, copy) NSString *subtitle;
@property (nonatomic) BOOL animatesDrop;
@property (nonatomic) BOOL canShowCallout;

@property (copy) NSString *address;
@property (copy) NSNumber *identifier;
@property (nonatomic, copy) NSString *imageKey;
@property (nonatomic, copy) UIImage *image;

@end

import "MapPoint.h"

@implementation MapPoint

@synthesize title, subtitle, animatesDrop, canShowCallout, imageKey, image;
@synthesize address = _address, coordinate = _coordinate, identifier = _indentifier;

-(id)initWithAddress:(NSString *)address
       coordinate:(CLLocationCoordinate2D)coordinate
            title:(NSString *)t
       identifier:(NSNumber *)ident {
    self = [super init];

    if (self) {
        _address = [address copy];
        _coordinate = coordinate;
        _indentifier = ident;

        [self setTitle:t];

        NSDate *theDate = [NSDate date];

        subtitle = [NSDateFormatter localizedStringFromDate:theDate
                                              dateStyle:NSDateFormatterShortStyle
                                              timeStyle:NSDateFormatterShortStyle];
        }
    return self;
}

 - (void)encodeWithCoder:(NSCoder *)aCoder {

    [aCoder encodeObject:_address forKey:@"address"];


    [aCoder encodeObject:title forKey:@"title"];
    [aCoder encodeObject:_indentifier forKey:@"identifier"];
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super init];
    if (self) {
        [self setAddress:[aDecoder decodeObjectForKey:@"address"]];

    }
    return self;
}

@end

Cajole answered 10/1, 2013 at 22:54 Comment(3)
What is the error/behavior you are getting?Glooming
What do you mean by "encoding the CLLocationCoordinate2D"? To Base-64? Or what?Exhilarative
So I am trying to encode the CLLocationCoordinate2D variable, but when I try [aCoder encodeObject:_coordinate forKey:@"Coord"]; I get the error Sending 'CLLocationCoordinate2D' perimeter of incompatible type 'id'Cajole
A
17

Just encode the two fields of the CLLocationCoordinate2D value.

[aCoder encodeDouble:_coordinate.latitude forKey:@"latitude"];
[aCoder encodeDouble:_coordinate.longitude forKey:@"longitude"];
Accoutre answered 11/1, 2013 at 0:33 Comment(0)
H
11

NSValue is NSCoding compliant. You can box your CLLocationcoordinate2D variable in an NSValue object:

 [coder encodeObject:[NSValue valueWithMKCoordinate:coordinate] forKey:@"coordinate"]
Humoral answered 14/2, 2014 at 16:42 Comment(2)
Nice one, worth to add that you have to add #import "MapKit/MapKit.h" (and MapKit framework).Rosinweed
When i tried to encode CLLocationCoordinate2D, it produced an error "-[NSKeyedArchiver encodeValueOfObjCType:at:]: this archiver cannot encode structs'". Tell me what i am doing wrong here.Laudable
A
4

The CLLocationCoordinate2D's latitude and longitude are of type CLLocationDegrees which is, essentially, a fancy way of saying double.

This is how you can encode and decode them:

NSString *const kPinCoordinateLatitudeKey = @"kPinCoordinateLatitudeKey";
NSString *const kPinCoordinateLongitudeKey = @"kPinCoordinateLongitudeKey";

- (void)encodeWithCoder:(NSCoder *)encoder
{
    [encoder encodeDouble:self.coordinate.latitude forKey:kPinCoordinateLatitudeKey];
    [encoder encodeDouble:self.coordinate.longitude forKey:kPinCoordinateLongitudeKey];
}

- (id)initWithCoder:(NSCoder *)decoder
{
    if((self = [super init])) {
        CLLocationDegrees latitude = [decoder decodeDoubleForKey:kPinCoordinateLatitudeKey];
        CLLocationDegrees longitude = [decoder decodeDoubleForKey:kPinCoordinateLongitudeKey];
        _coordinate = CLLocationCoordinate2DMake(latitude, longitude);
    }
    return self;
}
Amygdalin answered 5/9, 2014 at 10:4 Comment(0)
C
2

I decided to encode use a CLLocation property handle this situation, which conforms to NSSecureCoding.

If you need to convert to or from a CLLocationCoordinate2D:

// Coordinate to Location
CLLocationCoordinate2D coord;
CLLocation *loc = [[CLLocation alloc] initWithLatitude:coord.latitude
                                             longitude:coord.longitude];

// Location to Coordinate
CLLocationCoordinate2D coord = loc.coordinate;
Chryso answered 5/11, 2016 at 22:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.