Volker's answer does point out one important issue:
The first time the user adds a pin, there will be no array already saved in the user defaults so pinCoords
will be nil
. Therefore, the addObject
calls on the array will do nothing. You need to handle this case by allocating an empty array if it's nil
so you can add objects to it.
However, there are still other issues in addPinToMap:
that will prevent the code from working even after fixing the above:
- The
pindict
variable is declared but never allocated. This will either lead to a crash when you callsetObject:forKey:
on it or do nothing. You need to allocate thepindict
variable. - With
NSUserDefaults
,objectForKey:
will return an immutable object. That means even thoughpincoords
is declared as anNSMutableArray
,objectForKey:
will return anNSArray
(if it finds a value for the key in user defaults). Therefore, theaddObject
calls will again fail (this time with a crash) since you can't add objects to anNSArray
. What you need to do is take the result ofobjectForKey:
and make a mutable version of it by callingmutableCopy
. - After adding the new coordinates to
pinCoords
, the code does not save the updated array back to user defaults. It just callssynchronize
. Before callingsynchronize
, you need to actually save the array to user defaults by callingsetObject:forKey:
.
After making all the above changes, the code should work.
I also recommend two more changes to improve the code (though these aren't preventing it from working):
- Instead of saving the coordinates as
float
values, save them asdouble
. The latitude and longitude in Core Location are actually of typedouble
(CLLocationDegrees
is actually a double). You'll also get better precision. So inaddPinToMap:
, usenumberWithDouble
instead ofnumberWithFloat
and inviewDidLoad
, usedoubleValue
instead offloatValue
. - In
viewDidLoad
, inside thefor
loop, you are callingsynchronize
twice. These calls are pointless -- remove them.
The final, updated code in addPinToMap:
would be this:
- (void)addPinToMap:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView];
CLLocationCoordinate2D touchMapCoordinate = [self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];
NSMutableDictionary *pindict = [NSMutableDictionary dictionary];
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSMutableArray *pincoords = [[def objectForKey:@"saveCoords"] mutableCopy];
if (pincoords == nil)
{
pincoords = [NSMutableArray array];
}
CLLocationCoordinate2D coordinates;
coordinates.latitude = touchMapCoordinate.latitude;
coordinates.longitude = touchMapCoordinate.longitude;
NSNumber* latDegrees = [NSNumber numberWithDouble:touchMapCoordinate.latitude];
NSNumber* longDegrees = [NSNumber numberWithDouble:touchMapCoordinate.longitude];
[pindict setObject:latDegrees forKey:@"pinlat"];
[pindict setObject:longDegrees forKey:@"pinlong"];
MapAnnotation *toAdd = [[MapAnnotation alloc]init];
toAdd.coordinate = coordinates;
toAdd.title = @"Svampe Spot";
[self.mapView addAnnotation:toAdd];
[pincoords addObject:pindict];
[def setObject:pincoords forKey:@"saveCoords"];
[def synchronize];
}
The updated for
loop in viewDidLoad
would be like this:
for (NSDictionary *pindict in pincoords) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(
[[pindict objectForKey:@"pinlat"] doubleValue],
[[pindict objectForKey:@"pinlong"] doubleValue]);
MapAnnotation *mapPin = [[MapAnnotation alloc]init];
mapPin.coordinate = coordinate;
mapPin.title = @"Svampe Spot";
[self.map addAnnotation:mapPin];
}