In my app, I am trying to save the pins that are on the map so that they are there when the user opens the app after it is terminated. I have conformed my mkAnnotation class to NSCoding, and implemented the two required methods. The annotations are all stored in a NSMutableArray in a singleton class, so I am really just trying to save the array in the singleton class. Everything is being encoded fine, but I do not think they are being decoded. Here is some code: This is my MKAnnotation class:
#import <CoreLocation/CoreLocation.h>
#import <MapKit/MapKit.h>
@interface MapPoint : NSObject <MKAnnotation, NSCoding>
{
}
- (id)initWithAddress:(NSString*)address
coordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)t;
@property (nonatomic, readwrite) 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 (nonatomic, copy) NSString *imageKey;
@property (nonatomic, copy) UIImage *image;
@end
@implementation MapPoint
@synthesize title, subtitle, animatesDrop, canShowCallout, imageKey, image;
@synthesize address = _address, coordinate = _coordinate;
-(id)initWithAddress:(NSString *)address
coordinate:(CLLocationCoordinate2D)coordinate
title:(NSString *)t {
self = [super init];
if (self) {
_address = [address copy];
_coordinate = coordinate;
[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"];
NSLog(@"ENCODING coordLatitude %f coordLongitude %f ", _coordinate.latitude, _coordinate.longitude);
[aCoder encodeDouble:_coordinate.longitude forKey:@"coordinate.longitude"];
[aCoder encodeDouble:_coordinate.latitude forKey:@"coordinate.latitude"];
[aCoder encodeObject:title forKey:@"title"];
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super init];
if (self) {
[self setAddress:[aDecoder decodeObjectForKey:@"address"]];
NSLog(@"DECODING coordLatitude %f coordLongitude %f ", _coordinate.latitude, _coordinate.longitude);
_coordinate.longitude = [aDecoder decodeDoubleForKey:@"coordinate.longitude"];
_coordinate.latitude = [aDecoder decodeDoubleForKey:@"coordinate.latitude"];
[self setTitle:[aDecoder decodeObjectForKey:@"title"]];
}
return self;
}
@end
Here is my singleton class:
#import <Foundation/Foundation.h>
@class MapPoint;
@interface Data : NSObject
{
NSMutableArray *_annotations;
}
@property (retain, nonatomic) NSMutableArray *annotations;
+ (Data *)singleton;
- (NSString *)pinArchivePath;
- (BOOL)saveChanges;
@end
@implementation Data
@synthesize annotations = _annotations;
+ (Data *)singleton {
static dispatch_once_t pred;
static Data *shared = nil;
dispatch_once(&pred, ^{
shared = [[Data alloc] init];
shared.annotations = [[NSMutableArray alloc]init];
});
return shared;
}
- (id)init {
self = [super init];
if (self) {
NSString *path = [self pinArchivePath];
_annotations = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
if (!_annotations) {
_annotations = [[NSMutableArray alloc]init];
}
}
return self;
}
- (NSString *)pinArchivePath {
NSArray *cachesDirectories = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
NSString *cachesDirectory = [cachesDirectories objectAtIndex:0];
return [cachesDirectory stringByAppendingPathComponent:@"pins.archive"];
}
- (BOOL)saveChanges {
NSString *path = [self pinArchivePath];
return [NSKeyedArchiver archiveRootObject:[Data singleton].annotations
toFile:path];
}
@end
In my viewDidLoad method on the map view controller, I try and place the annotations in the singleton array on the map with this:
for (MapPoint *mp in [Data singleton].annotations) {
[_worldView addAnnotation:mp];
}
The main problem is in the singleton
method in these lines:
dispatch_once(&pred, ^{
shared = [[Data alloc] init];
shared.annotations = [[NSMutableArray alloc]init]; //<-- problem line
});
The shared = [[Data alloc] init];
line decodes and initializes the annotations
array.
Then the shared.annotations = [[NSMutableArray alloc]init];
line re-creates and re-initializes the annotations
array thus discarding the just-decoded annotations so the singleton always returns an empty array.
Remove the shared.annotations = [[NSMutableArray alloc]init];
line.
As already mentioned in the comment, the other minor issue, which causes simply confusion, is the placement of the NSLog
where the coordinate is being decoded. The NSLog
should be after the decode is done.