【问题标题】:Annotation map pin title showing wrongly注释地图图钉标题显示错误
【发布时间】:2014-07-31 17:32:36
【问题描述】:

注释图钉标题为所有图钉显示相同的标题。我已设置标签以显示每个图钉的标题,但我得到所有标签的相同标题。我做了NSLog 的 lbl.text 和 NSLog 它显示不同的标题。

为什么我得到所有地图图钉的相同标题。

    -(void)maprequests
    {

    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    // getting an NSString
    NSString *emailid = [prefs stringForKey:@"email"];
    NSString *deviceid = [Request UDID];
    //NSString * walkGUID=[prefs stringForKey:@"walkguid"];
    //NSLog(@"walkGUID:%@",walkGUID);
    NSString * walkguid=[prefs stringForKey:@"walkguid"];

    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"http://10.0.0.28/web/ws/get_poilist_walks.php?strEmailID=%@&strDeviceID=%@&strWalkGuid=%@",emailid,deviceid,walkguid]];

    NSLog(@"%@",url);

    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    //AFNetworking asynchronous url request
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];

    operation.responseSerializer = [AFJSONResponseSerializer serializer];
    operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {

        self.pointofintrests = [responseObject objectForKey:@"PointOfIntrests"];
                NSIndexPath *indexpath;

        NSDictionary *tempDictionary= [self.pointofintrests objectAtIndex:indexpath.row];

        for (NSDictionary *dictionary in _pointofintrests)
        {
            MKCoordinateRegion region = { {0.0, 0.0 }, { 0.0, 0.0 } };
            NSString * latitude= [dictionary objectForKey:@"Latitude"];
            NSString * longitude =[dictionary objectForKey:@"Longitude"];
            double strlatitude = [latitude doubleValue];
            double strlongitude = [longitude doubleValue];
            region.center.latitude =strlatitude;
            region.center.longitude =  strlongitude;
            region.span.longitudeDelta = 0.01f;
            region.span.latitudeDelta = 0.01f;
            [_mapview setRegion:region animated:YES];
            [_mapview setDelegate:self];

            DisplayMap *ann = [[DisplayMap alloc] init];
            ann.coordinate = region.center;

            [_mapview addAnnotation:ann];

        }

    }
     failure:^(AFHTTPRequestOperation *operation, NSError *error)
     {
        NSLog(@"Request Failed: %@, %@", error, error.userInfo);

    }];

    [operation start];



}

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation{

    MKPinAnnotationView *pinView = nil;
    UILabel *label;
    if(annotation != mapView.userLocation)
    {

        static NSString *defaultPinID = @"com.invasivecode.pin";
        pinView = (MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
        if ( pinView == nil ) pinView = [[MKPinAnnotationView alloc]
                                         initWithAnnotation:annotation reuseIdentifier:defaultPinID];

        if(![annotation isKindOfClass:[DisplayMap class]])
            return nil;

        DisplayMap *a = (DisplayMap *)annotation;
        pinView.image=[UIImage imageNamed:@"push_pin@2x"];


        UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 250, 30)];
        lbl.backgroundColor = [UIColor clearColor];
        lbl.textColor = [UIColor whiteColor];
        lbl.alpha = 0.5;
        lbl.tag = 42;
        for (int i=0; i<_pointofintrests.count; i++)
        {
        lbl.text = [[_pointofintrests valueForKey:@"title"] objectAtIndex:i];
        }
        [pinView addSubview:lbl];

        [_mapview selectAnnotation:pinView animated:YES];

        pinView.canShowCallout = YES;
        pinView.animatesDrop = NO;

    }
    else
    {


    }


     return pinView;

   }

【问题讨论】:

  • 将注释的标题属性设置为标题添加注释时,然后您可以将 lbl.text 设置为 annotation.title(无需查找任何内容,因为数据将与注释对象本身)。
  • 此代码还有很多其他问题(处理注释视图重用等)。

标签: ios objective-c ios7 mkmapview mkannotationview


【解决方案1】:

你的问题是你在循环_pointofinterests

for (int i=0; i<_pointofintrests.count; i++)
{
    lbl.text = [[_pointofintrests valueForKey:@"title"] objectAtIndex:i];
}

这不是你想的那样。它将数组中的最后一个标题分配给每个引脚。

因为viewForAnnotation 委托方法为您提供了将要显示的注释,所以我倾向于保留一组注释来保存索引,因此您可以正确访问您的数据。

当您调用[_mapview addAnnotation:ann]; 时,还将ann 保存到一个数组中。

然后您应该能够执行以下操作:

[[_pointofintrests valueForKey:@"title"] objectAtIndex:[annArray indexOfObject:annotation]]

附带说明,如果_pointofinterests 是NSDictionary,我会改用objectForKey。

【讨论】:

    【解决方案2】:

    您在所有引脚上获得相同标签文本的主要原因是,正如在另一个答案中已经指出的那样,对于每个引脚,lbl.text 始终设置为_pointofintrests 中最后一个对象的标题。

    我更喜欢的解决方案是设置注释的title 并使用它来设置标签的文本。

    1. 在创建注解时和调用addAnnotation之前,设置它的title属性:

      DisplayMap *ann = [[DisplayMap alloc] init];
      ann.coordinate = region.center;
      ann.title = [dictionary objectForKey:@"title"];  //<-- add this line
      [_mapview addAnnotation:ann];
      
    2. 在viewForAnnotation 中,您可以简单地将标签的文本设置为注释的标题,而不是for 循环(不搜索数组或循环):

      //for (int i=0; i<_pointofintrests.count; i++)
      //{
      //    lbl.text = [[_pointofintrests valueForKey:@"title"] objectAtIndex:i];
      //}
      
      lbl.text = annotation.title;
      


    这从技术上解决了所有图钉上出现相同文本的问题。

    但是,viewForAnnotation 中的代码还有一些其他问题,这些问题在上述修复后会变得明显:

    • UILabel 被添加到注释视图中,即使注释视图已出列(意味着重新使用先前创建的视图)。该出列视图将已经在其中包含UILabel,并且现有代码将在顶部添加另一个。平移和缩放地图一段时间后,您会注意到每个图钉的标签重叠。

      UILabel 仅应在创建新视图时添加(当 dequeue 返回 nil 而您 alloc+init 是一个新视图时)。

    • 另一个问题是,由于您使用自定义图像进行注释,因此您应该创建一个普通的MKAnnotationView 而不是MKPinAnnotationView。 MKPinAnnotationView 类旨在显示标准的内置 pin 图像,尽管它仍然具有 image 属性,但它有时往往会忽略它并恢复显示其标准 pin 图像。

    • 另一个问题是这一行:

      [_mapview selectAnnotation:pinView animated:YES];
      
      • 地图视图一次只能“选择”一个注释,因此如果您认为在 viewForAnnotation 中调用它会同时显示所有注释的标注,那就大错特错了。
      • selectAnnotation 方法需要 注解 作为第一个参数。 pinView 不是注解——它是注解的view(它们不是一回事)。编译器一定会抱怨这一行,并且在运行时,系统可能会在控制台中显示一个错误,例如“尝试选择尚未添加的注释”。所以从技术上讲,这条线应该是[_mapview selectAnnotation:annotation animated:YES];
      • 无论如何,不​​要在 viewForAnnotation 委托方法中调用 selectAnnotation。 这样做可能会导致递归和堆栈溢出(以及 EXC_BAD_ACCESS),因为选择会导致注释的视图被更新,从而导致要调用 viewForAnnotation 等。相反,请在 didAddAnnotationViews 委托方法中为要显示标注的 one 注释调用它。

    您修改后的 viewForAnnotation 委托方法可能如下所示:

    -(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
    {
        if(! [annotation isKindOfClass:[DisplayMap class]])
        {
            return nil;
        }
    
        static NSString *defaultPinID = @"MyPin";
    
        int lblTag = 42;
    
        MKAnnotationView *pinView = [mapView dequeueReusableAnnotationViewWithIdentifier:defaultPinID];
        if (pinView == nil)
        {
            pinView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:defaultPinID];
            pinView.image = [UIImage imageNamed:@"push_pin@2x"];
            pinView.canShowCallout = YES;
    
            //Create and add the label to the view ONCE when creating the view... 
            UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(10, 30, 250, 30)];
            lbl.backgroundColor = [UIColor clearColor];
            lbl.textColor = [UIColor whiteColor];
            lbl.alpha = 0.5;
            lbl.tag = lblTag;
            [pinView addSubview:lbl];
        }
        else
        {
            //If we are re-using a dequeued view
            //update its annotation reference...
            //(otherwise view will still be pointing to its previous annotation)
            pinView.annotation = annotation;
        }
    
        //At this point, we have a new or dequeued view 
        //pointing to the current annotation.
        //Now update the label that will already be there
        //with the current annotation's title...
        UILabel *lbl = (UILabel *)[pinView viewWithTag:lblTag];
        lbl.text = annotation.title;
    
        return pinView;
    }
    

    请记住,您还需要设置注释的 title,如答案顶部所示。


    maprequests方法中的for循环也有一些东西我想指出:

    • 不必为了设置注解的坐标而创建和设置区域。在循环中调用setRegion 毫无意义且效率低下,因为无论如何用户最终只会看到位于最后一个注释处的地图。要设置注释坐标,只需:

      ann.coordinate = CLLocationCoordinate2DMake(strlatitude, strlongitude);
      
    • 您可以在for 循环之后调用setRegion(一次)(或者只调用[_mapview showAnnotations:_mapview.annotations animated:YES];,这样您就不必自己计算显示所有注释)。

    • 您不需要在for 循环内重复设置地图视图的delegate。在for 循环之前设置delegate(一次)之前(尽管它应该在调用此方法之前很久就设置好了)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多