将UIImage传递到MKPinAnnotationView时遇到问题



我对MKPointAnnotation进行了子类化,并添加了NSStringUIImage,这样我就可以将这些元素传递给MKPinAnnotationView。字符串进入MKPinAnnotationViewfine,但image属性为null。我不明白为什么。我会说,有一次在我的手机上运行这个代码,图像出现在一个引脚上一次,所以也许我有内存泄漏?我编译过的另外1000次图像在日志中显示为null,并且不会出现。感谢您的帮助。

这是我的子类customMapAnnotation.h:

@interface customMapAnnotation : MKPointAnnotation
@property (strong, nonatomic) NSString *restaurantID;
@property (strong, nonatomic) UIImage *restaurantIcon;
@end

这是我的customMapAnnotation的创建位置。我使用的是Parse.com,所以这里有一个语句可以将PFFile转换为UIImage。如果我检查日志,我会确认foodPoint.restaurantIcon在运行时有一个值。

customMapAnnotation *foodPoint = [[customMapAnnotation alloc] init];
foodPoint.coordinate = spot;
foodPoint.restaurantID = [object objectId];
foodPoint.title = [object objectForKey:@"restaurantName"];
foodPoint.subtitle = [object objectForKey:@"cuisineType"];
leftIcon = [object objectForKey:@"restaurantImage"];
[leftIcon getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
image = [UIImage imageWithData:data];
// image can now be set on a UIImageView
foodPoint.restaurantIcon = image;
}
}];
[self.mainMap addAnnotation:foodPoint];

现在这是我的MKPinAnnotationView的所有代码。请注意,我运行了一个NSLog来确认fp.restaurantIcon是否有值,并且它是null。我知道NSLog的这种使用并不优雅,但它应该返回图像的存储位置。它返回为空。同样,我的另一个自定义属性fp.restaurantId运行良好。

- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation {
static NSString *identifier = @"RoutePinAnnotation";
if (annotation == mapView.userLocation)
{
return nil;
}
else
{
MKPinAnnotationView *pinView = [[MKPinAnnotationView alloc]
initWithAnnotation:annotation reuseIdentifier:identifier];
pinView.animatesDrop=NO;
pinView.canShowCallout=YES;
UIButton *rightButton = [UIButton buttonWithType:UIButtonTypeDetailDisclosure];
//cast annotation parameter to our class so compiler understands...
customMapAnnotation *fp = (customMapAnnotation *)annotation;
NSLog(fp.restaurantIcon);
//get restaurantID from the annotation parameter ("fp")...
[rightButton setTitle:fp.restaurantID forState:UIControlStateNormal];
[rightButton addTarget:self
action:@selector(buttonMethod:)
forControlEvents:UIControlEventTouchUpInside];
pinView.rightCalloutAccessoryView = rightButton;
//NSLog(fp.restaurantIcon);
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:fp.restaurantIcon];
profileIconView.frame = CGRectMake(0,0,31,31);
pinView.leftCalloutAccessoryView = profileIconView;
return pinView;
}
}

这是我的didSelectAnnotationView:

- (void) mainMap:(MKMapView *)mainMap didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view.annotation isKindOfClass:[chwMapAnnotation class]])
{
chwMapAnnotation *fp = (chwMapAnnotation *)view.annotation;
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:fp.restaurantIcon];
profileIconView.frame = CGRectMake(0,0,31,31);
view.leftCalloutAccessoryView = profileIconView;
}
}

我同意@Vincent的评论,因为图像是异步加载在后台的,所以在调用viewForAnnotation时还没有加载,所以注释的callout被一个空白的左图标卡住了。

getDataInBackgroundWithBlock完成图像加载时,没有自动信号告诉注释视图刷新其leftCalloutAccessoryView

在这种情况下,粗略的解决方法是在选择注释时手动强制刷新leftCalloutAccessoryView(此时将显示包含leftCalloutAccessoryView的标注)。

选择注释后,地图视图将调用didSelectAnnotationView委托方法。在这里,可以应用粗略的变通方法:

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view
{
if ([view.annotation isKindOfClass:[customMapAnnotation class]])
{
customMapAnnotation *fp = (customMapAnnotation *)view.annotation;
UIImageView *profileIconView = [[UIImageView alloc] initWithImage:fp.restaurantIcon];
profileIconView.frame = CGRectMake(0,0,31,31);
view.leftCalloutAccessoryView = profileIconView;
}
}

当然,有可能图像仍然没有为所选的注释加载(要么只是花了很长时间,要么图像url无效,等等)。

您可以做的是在viewForAnnotation中,如果fp.restaurantIconnil,则将左侧图标设置为添加到项目资源中的某个通用"加载"图标。在didSelectAnnotationView中,您还可以首先检查fp.restaurantIcon是否仍然是nil,如果是,则不执行任何操作(即,将图标保留为通用的"加载"图标)。

一个不那么粗糙的解决方案可能是创建一个自定义注释视图类,该类从关联的注释中侦听"图像加载完成"消息并自动刷新自身。

我想说的是,不要尝试子类化MKPointAnnotation,创建符合MKAnnotation协议的自己的对象,并使用非MKPinAnnotationView的注释视图。