MKAnnotationView是否缓冲其输入队列? [英] does MKAnnotationView buffer its input queue?

查看:116
本文介绍了MKAnnotationView是否缓冲其输入队列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想根据它们表示的相对时间在UIMapView中显示不同颜色的引脚

,但是它似乎mapView:viewForAnnotation:方法只是它的事情独立于它的调用。



在我的代码示例中,我已经检索更早&较新的位置从文件到self.fileArray。
数组包含具有age属性的调查结果的对象。
最新的发现将生命开始为age @0,并且每次重新加载数组以准备接受新发现
时,它们分别在年龄上分别变为@1和@2,之后它们然后删除。



一旦他们接受他们的新的年龄属性,他们被发送到mapView:viewForAnnotation:method
根据他们的新状态显示为I迭代通过fileArray



实际的问题是跳转后。很多有趣的其他答案在制定问题时出现,但没有一个适用于我的情况。

 

int size = [self.fileArray count];
for(int idx =(size-1); idx> 0; idx--)// process backwards
{
annotationFlag = 0; // using a global just for now
self.finding = self.fileArray [idx];
if([self.finding.age isEqualToString:@2]){
[self.fileArray removeObjectAtIndex:idx];
}

if([self.finding.age isEqualToString:@1]){
self.finding.age = @2;
[self.fileArray replaceObjectAtIndex:idx withObject:self.finding];
annotationFlag = 2;

//尝试这里,只显示最新的
}

if([self.finding.age isEqualToString:@0]){
self.finding.age = @1;
[self.fileArray replaceObjectAtIndex:idx withObject:self.finding];
annotationFlag = 1;

//尝试这里,仍然只显示相同的最新
}

} // end if

//< Breakpoint与此处的日志>

MKPointAnnotation * annotation = [[MKPointAnnotation alloc] init];
CLLocationCoordinate2D myCoordinate;
myCoordinate.latitude = [self.finding.myLat doubleValue];
myCoordinate.longitude = [self.finding.myLong doubleValue];
annotation.coordinate = myCoordinate;
[self.mapView addAnnotation:annotation];
} // end for


注释方法是相当标准的,大多数人都使用:

   - (void)mapView:(MKMapView *)mapView didUpdateUserLocation:(MKUserLocation *)userLocation {
_mapView.centerCoordinate = userLocation.location.coordinate;



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

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

static NSString * identifier = @myAnnotation;
MKPinAnnotationView * annotationView =(MKPinAnnotationView *)[self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if(!annotationView)
{
annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];

//< Breakpoint with Log here>

switch(annotationFlag){
case 1:
annotationView.pinColor = MKPinAnnotationColorGreen;
break;
case 2:
annotationView.pinColor = MKPinAnnotationColorRed;
break;
默认值:
annotationView.pinColor = MKPinAnnotationColorPurple;
break;
}
annotationView.animatesDrop = YES;
annotationView.canShowCallout = NO;
} else {
annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeSystem]; // UIButtonTypeDetailDisclosure
return annotationView;
}

也是我的邻居狗的好奇心。每个pin的pin应该显示不同的颜色



如果我NSLog annotationFlag到控制台在各个点mapView:viewForAnnotation:似乎是
忽略annotationFlag中的值,并且只使用状态最后设置,导致我相信它只作用
for循环完全完成,而不是后续的迭代。



所以问题是,为什么不是[self.mapView addAnnotation:annotation]立即采取行动。



LATE编辑:
使用断点和日志到控制台的组合如上面的列表中所示,并且注释年龄增加处理导致42个元素(包括准备被丢弃的旧元素)的数组,因此42个引脚要被删除。



当达到mapView:viewForAnnotation方法时,我必须重新执行42次,而在43rd,所有的引脚立即下降。仔细观察它的相同的颜色,所以我可以验证最后使用的颜色不画任何早先的颜色。

不能保证 viewForAnnotation 将在 addAnnotation 之后立即调用,或者它将只被调用一次。



注释可以添加到当前不可见的区域,或者用户可能平移或缩放地图,导致注释返回视图。地图视图将根据需要随时或频繁地调用它。



这是一个按设计和简单的委托方法。



因此,您委托方法的实现通常只使用传递给方法的注解参数方法内所有逻辑的基础。



有关可以更详细解释此问题的其他答案,请参阅:





对于您的问题,我建议如下:


  1. 现在您正在添加类型 MKPointAnnotation 的注释,它们不包含 viewForAnnotation 方法的age信息需要(我假设这是它需要的)。



    不要使用 MKPointAnnotation ,请使用 Finding (或任何类型的 self.finding 对象)实现 MKAnnotation 协议本身。你应该可以在SO上找到自定义注释类的几个例子。



    然后,而不是保留 annotationFlag 变量并创建 MKPointAnnotation 对象,直接将对象本身(包含它们的age)添加到映射中 viewForAnnotation 中调用 addAnnotation


  2. pinColor 之后的设置为创建/退出视图的if-else,并且在 return 。请务必根据传递到方法中的注释对象的age属性设置 pinColor 查找类型对象)。例如:

       - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation 
    {
    if([annotation isKindOfClass:[MKUserLocation class]])
    return nil;

    static NSString * identifier = @myAnnotation;
    MKPinAnnotationView * annotationView =(MKPinAnnotationView *)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
    if(!annotationView)
    {
    annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier]
    annotationView.animatesDrop = YES;
    annotationView.canShowCallout = NO;
    annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeSystem];
    } else {
    annotationView.annotation = annotation;
    }

    //在视图中更新pinColor是否是一个新的OR出列视图...
    if([annotation isKindOfClass:[Finding class]])
    {
    Finding * f =(Finding *)annotation;

    if([f.age isEqualToString:@2]){
    annotationView.pinColor = MKPinAnnotationColorGreen;
    }
    else if([f.age isEqualToString:@1]){
    annotationView.pinColor = MKPinAnnotationColorPurple;
    }
    else {
    annotationView.pinColor = MKPinAnnotationColorRed;
    }
    }

    return annotationView;
    }



I want to display different colour pins in a UIMapView based on the relative time they represent
but it seems the mapView:viewForAnnotation: method only does it's thing independent of when its called.

In my code example I have already retrieved earlier & newer locations from a file to self.fileArray . the array holds objects called findings that has (among others) an age property . newest findings start life as age @"0", and each time the array is reloaded ready to take new findings they progress in age to @"1" and @"2" respectively after which they are then dropped.

Once they take on their new age property they are sent to the mapView:viewForAnnotation: method to be displayed according to their new status as I iterate through the fileArray

the actual question is after the jump. A lot of interesting other-answers cropped up while formulating the question but none quite applied to my case

.
.
int size = [self.fileArray count];
for (int idx=(size-1); idx>0; idx--)  // process backwards
    {
        annotationFlag = 0;           // using a global just for now
    self.finding = self.fileArray[idx];
        if ([self.finding.age isEqualToString:@"2"]) {
            [self.fileArray removeObjectAtIndex:idx];
        }

        if ([self.finding.age isEqualToString:@"1"]) {
            self.finding.age = @"2";
            [self.fileArray replaceObjectAtIndex:idx withObject:self.finding];
            annotationFlag = 2;

            // tried here , only displays the newest
        }

        if ([self.finding.age isEqualToString:@"0"]) {
            self.finding.age = @"1";
            [self.fileArray replaceObjectAtIndex:idx withObject:self.finding];
            annotationFlag = 1;

            // tried here, still only displays the same newest 
        }

    }   // end if

//<Breakpoint with Log here> 

    MKPointAnnotation* annotation = [[MKPointAnnotation alloc] init];
    CLLocationCoordinate2D myCoordinate;
    myCoordinate.latitude =[self.finding.myLat doubleValue];
    myCoordinate.longitude=[self.finding.myLong doubleValue];
    annotation.coordinate = myCoordinate;
    [self.mapView addAnnotation:annotation];
}       // end for 
.
.

the annotation methods are fairly standard, as used by most everybody:

- (void)mapView:(MKMapView *)mapView didUpdateUserLocation: (MKUserLocation *)userLocation {
_mapView.centerCoordinate = userLocation.location.coordinate;
}


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

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

static NSString *identifier = @"myAnnotation";
MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[ self.mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
if (!annotationView)
{
    annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];

//<Breakpoint with Log here>

    switch (annotationFlag) {
        case 1:
        annotationView.pinColor = MKPinAnnotationColorGreen;
            break;
        case 2:
        annotationView.pinColor = MKPinAnnotationColorRed;
            break;
        default:
        annotationView.pinColor = MKPinAnnotationColorPurple;
        break;
    }
    annotationView.animatesDrop = YES;
    annotationView.canShowCallout = NO;
}else {
    annotationView.annotation = annotation;
}
annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeSystem]; // UIButtonTypeDetailDisclosure
return annotationView;
}

also under test is my neighbours dogs curiosity. the pins should show different colours for each foray

If I NSLog annotationFlag to console at various points mapView:viewForAnnotation: seems to be ignoring the values in annotationFlag and only using the state last set, leading me to believe it is only acting when the for loop is entirely finished, and not following iterations.

so the question is, why isn't the [self.mapView addAnnotation:annotation] call acting immediately. Ive put it within the for loop, and there is no doubling up happening there.

LATE EDIT: using a combination of breakpoints and log-to-consoles as shown in the listings above, and commenting out the age increase processing results in an array of 42 elements ( including the old ones ready to be discarded ) and therefore 42 pins to be dropped.

When the mapView:viewForAnnotation method is reached I then have to step through for another 42 times and on the 43rd all the pins drop at once. Watching carefully its the same colour so I can verify the last colour used doesn't draw over any earlier ones. If that clarifies the problem.

解决方案

There is no guarantee that the viewForAnnotation will be called immediately after addAnnotation or that it will be called only once.

The annotation could be added in a region that isn't currently visible or the user might pan or zoom the map which causes the annotation to come back into view. The map view will simply call it whenever or as often as it needs to.

This is by-design and simply how the delegate method approach works.

For this reason, your implementation of the delegate method should generally only use the annotation parameter passed to the method as the basis for all the logic inside the method. It should not rely on any external variables or make broad assumptions about when it will be called.

For other answers that may explain this in more detail, see:

For your question specifically, I suggest the following:

  1. Right now you're adding annotations of type MKPointAnnotation which don't contain the "age" information that the viewForAnnotation method needs (I'm assuming this is what it needs).

    Instead of using MKPointAnnotation, make your Finding class (or whatever the type is of the self.finding object) implement the MKAnnotation protocol itself. You should be able to find several examples of custom annotation classes on SO.

    Then, instead of keeping an annotationFlag variable and creating MKPointAnnotation objects, add the Finding objects themselves (which contain their "age") directly to the map when calling addAnnotation.

  2. In viewForAnnotation, set the pinColor after the if-else that creates/dequeues the view and just before the return. Be sure to set the pinColor based on the age property of the annotation object passed into the method (which will be a Finding type object). For example:

    - (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id)annotation 
    {
        if([annotation isKindOfClass:[MKUserLocation class]])
            return nil;
    
        static NSString *identifier = @"myAnnotation";
        MKPinAnnotationView * annotationView = (MKPinAnnotationView*)[mapView dequeueReusableAnnotationViewWithIdentifier:identifier];
        if (!annotationView)
        {
            annotationView = [[MKPinAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:identifier];
            annotationView.animatesDrop = YES;
            annotationView.canShowCallout = NO;
            annotationView.rightCalloutAccessoryView = [UIButton buttonWithType:UIButtonTypeSystem];
        }else {
            annotationView.annotation = annotation;
        }
    
        //update the pinColor in the view whether it's a new OR dequeued view...
        if ([annotation isKindOfClass:[Finding class]])
        {
            Finding *f = (Finding *)annotation;
    
            if ([f.age isEqualToString:@"2"]) {
                annotationView.pinColor = MKPinAnnotationColorGreen;
            }
            else if ([f.age isEqualToString:@"1"]) {
                annotationView.pinColor = MKPinAnnotationColorPurple;
            }
            else {
                annotationView.pinColor = MKPinAnnotationColorRed;
            }
        }
    
        return annotationView;
    }
    

这篇关于MKAnnotationView是否缓冲其输入队列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆