使用NSMutableArray保存和加载MapAnnotation引脚 [英] Save and Load MapAnnotation pins using NSMutableArray
问题描述
我需要有关MapAnnotation代码的帮助.我想保存地图图钉,以便用户可以返回地图并查看他/她放置的图钉.
I need help with my MapAnnotation codes. I want to save map pins so that the user can come back to the map and see the ones he/she has placed.
但是,此代码在视图加载时不显示引脚.
However this code does not show the pins when the view loads.
添加和保存密码的代码:
Code for adding and saving pins:
- (void)addPinToMap:(UIGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state != UIGestureRecognizerStateBegan)
return;
CGPoint touchPoint = [gestureRecognizer locationInView:self.mapView];
CLLocationCoordinate2D touchMapCoordinate =
[self.mapView convertPoint:touchPoint toCoordinateFromView:self.mapView];
//NSMutableArray *pincoords = (NSMutableArray *)[[NSUserDefaults standardUserDefaults] objectForKey:@"saveCoords"];
NSMutableDictionary *pindict;
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSMutableArray *pincoords = [def objectForKey:@"saveCoords"];
CLLocationCoordinate2D coordinates;
coordinates.latitude = touchMapCoordinate.latitude;
coordinates.longitude = touchMapCoordinate.longitude;
NSNumber* latDegrees = [NSNumber numberWithFloat:touchMapCoordinate.latitude];
NSNumber* longDegrees = [NSNumber numberWithFloat: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 synchronize];
}
我的加载代码:
- (void)viewDidLoad
{
[super viewDidLoad];
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSMutableArray *pincoords = [def objectForKey:@"saveCoords"];
for (NSDictionary *pindict in pincoords) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake([[pindict objectForKey:@"pinlat"] floatValue], [[pindict objectForKey:@"pinlong"] floatValue]);
MapAnnotation *mapPin = [[MapAnnotation alloc]init];
mapPin.coordinate = coordinate;
mapPin.title = @"Svampe Spot";
[self.mapView addAnnotation:mapPin];
[def synchronize];
[def synchronize];
}
}
一个解决方案将不胜感激!
A solution would be much appreciated!!
删除特定注释的代码:
- (void)mapView:(MKMapView *)mapView annotationView:(MKAnnotationView *)mapViewpin
calloutAccessoryControlTapped:(UIControl *)control {
NSUserDefaults *def = [NSUserDefaults standardUserDefaults];
NSMutableArray *pincoords = [def objectForKey:@"saveCoords"];
for (NSDictionary *pindict in pincoords) {
CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(
[[pindict objectForKey:@"pinlat"] doubleValue],
[[pindict objectForKey:@"pinlong"] doubleValue]);
MapAnnotation *mapPin = mapViewpin.annotation;
mapPin.coordinate =coordinate;
[self.mapView removeAnnotation:mapPin];
[def removeObjectForKey:@"saveCoords"];
[def synchronize];
}
}
这将全部删除.如何针对点击了谁的注解按钮特定它?
This deletes them all. How do i make it specific for the annotation whos button is tapped?
推荐答案
沃尔克的答案确实指出了一个重要问题:
Volker's answer does point out one important issue:
用户第一次添加引脚时,用户默认值将不会保存任何数组,因此pinCoords
将为nil
.因此,对数组的addObject
调用将无济于事.如果是nil
,则需要分配一个空数组来处理这种情况,以便向其添加对象.
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.
但是,addPinToMap:
中仍然存在其他问题,即使修复了上述问题,该问题也仍将阻止代码工作:
However, there are still other issues in addPinToMap:
that will prevent the code from working even after fixing the above:
- 已声明
pindict
变量 ,但从未已分配.当您在其上调用setObject:forKey:
时,这将导致崩溃或不执行任何操作.您需要分配pindict
变量. - 对于
NSUserDefaults
,objectForKey:
将返回不可变对象.这意味着即使将pincoords
声明为NSMutableArray
,objectForKey:
仍将返回NSArray
(如果它在用户默认值中找到了键的值).因此,由于无法将对象添加到NSArray
,因此addObject
调用将再次失败(这次是崩溃).您需要做的是获取objectForKey:
的结果,并通过调用mutableCopy
对其进行可变版本. - 将新坐标添加到
pinCoords
后,代码不会将更新后的数组保存回用户默认值.它只是调用synchronize
.在调用synchronize
之前,您需要通过调用setObject:forKey:
将数组实际保存为用户默认设置.
- 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):
- 将坐标另存为
double
,而不是将其另存为float
值.核心位置中的纬度和经度实际上是double
类型(CLLocationDegrees
实际上是双精度).您还将获得更好的精度.因此,在addPinToMap:
中,使用numberWithDouble
代替numberWithFloat
;在viewDidLoad
中,使用doubleValue
代替floatValue
. - 在
viewDidLoad
的for
循环内,您两次调用synchronize
.这些调用毫无意义-将其删除.
- 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.
addPinToMap:
中最终的,更新的代码是这样的:
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];
}
viewDidLoad
中更新的for
循环如下所示:
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];
}
这篇关于使用NSMutableArray保存和加载MapAnnotation引脚的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!