MKAnnotationView是否缓冲其输入队列? [英] does MKAnnotationView buffer its input queue?
问题描述
我想根据它们表示的相对时间在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
之后立即调用,或者它将只被调用一次。 注释可以添加到当前不可见的区域,或者用户可能平移或缩放地图,导致注释返回视图。地图视图将根据需要随时或频繁地调用它。
这是一个按设计和简单的委托方法。
因此,您委托方法的实现通常只使用传递给方法的注解
参数方法内所有逻辑的基础。
有关可以更详细解释此问题的其他答案,请参阅:
对于您的问题,我建议如下:
-
现在您正在添加类型
MKPointAnnotation
的注释,它们不包含viewForAnnotation
方法的age信息需要(我假设这是它需要的)。
不要使用
MKPointAnnotation
,请使用Finding
(或任何类型的self.finding
对象)实现MKAnnotation
协议本身。你应该可以在SO上找到自定义注释类的几个例子。
然后,而不是保留
annotationFlag
变量并创建MKPointAnnotation
对象,直接将对象本身(包含它们的age)添加到映射中
viewForAnnotation
中调用addAnnotation
。 - 将
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:
- Map view annotations with different pin colors
- MKMapview annotation dynamic pin image changes after zooming
- Map annotation display all the same image/pins for all points
- Setting Map Pin colour dynamically for iOS, etc
For your question specifically, I suggest the following:
Right now you're adding annotations of type
MKPointAnnotation
which don't contain the "age" information that theviewForAnnotation
method needs (I'm assuming this is what it needs).Instead of using
MKPointAnnotation
, make yourFinding
class (or whatever the type is of theself.finding
object) implement theMKAnnotation
protocol itself. You should be able to find several examples of custom annotation classes on SO.Then, instead of keeping an
annotationFlag
variable and creatingMKPointAnnotation
objects, add theFinding
objects themselves (which contain their "age") directly to the map when callingaddAnnotation
.In
viewForAnnotation
, set thepinColor
after the if-else that creates/dequeues the view and just before thereturn
. Be sure to set thepinColor
based on the age property of theannotation
object passed into the method (which will be aFinding
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屋!