Я читаю прекрасную лекцию CS193P о разработке iOS 5.0:
http://www.stanford.edu/class/cs193p/cgi-bin/drupal/
Я сейчас на задании № 5, обязательное задание № 5б. Мне нужно отображать выноску с миниатюрой, когда я нажимаю аннотацию на карте.
Мне удалось сделать это без проблем с помощью следующего кода (используя Flickr).
Мапвиевконтроллер.h:
@class MapViewController;
@protocol MapViewControllerDelegate <NSObject>
- (UIImage *)mapViewController:(MapViewController *)sender imageForAnnotation:(id <MKAnnotation>)annotation;
@end
@interface MapViewController : UIViewController
@property (nonatomic, strong) NSArray *annotations; // of id <MKAnnotation>
@property (nonatomic, weak) id <MapViewControllerDelegate> delegate;
@end
MapViewController.m:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)annotationView
{
if ([annotationView.leftCalloutAccessoryView isKindOfClass:[UIImageView class]]) {
UIImage *image = [self.delegate mapViewController:self imageForAnnotation:annotationView.annotation];
[(UIImageView *)annotationView.leftCalloutAccessoryView setImage:image];
}
}
PhotoListTableViewController.m:
@interface PhotoListTableViewController() <MapViewControllerDelegate>
- (UIImage *)mapViewController:(MapViewController *)sender imageForAnnotation:(id <MKAnnotation>)annotation
{
UIImage *image = nil;
if ([annotation isKindOfClass:[FlickrAnnotation class]]) { // make sure the annotation is a FlickrAnnotation
FlickrAnnotation *flickrAnnotation = (FlickrAnnotation *)annotation;
NSURL *photoUrl = [FlickrFetcher urlForPhoto:flickrAnnotation.photo format:FlickrPhotoFormatSquare];
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
}
return image;
}
@end
Я использую делегат в методе mapView:didSelectAnnotationView: MapViewController для извлечения изображения из другого контроллера, PhotoListTableViewController (чтобы убедиться, что у меня есть универсальный MapViewController).
Он работает нормально... но мне нужно изменить этот код, чтобы вызывать Flickr в другом потоке. Поэтому я изменил метод mapViewController:imageForAnnotation: для этого:
- (UIImage *)mapViewController:(MapViewController *)sender imageForAnnotation:(id <MKAnnotation>)annotation
{
__block UIImage *image = nil;
if ([annotation isKindOfClass:[FlickrAnnotation class]]) { // make sure the annotation is a FlickrAnnotation
FlickrAnnotation *flickrAnnotation = (FlickrAnnotation *)annotation;
dispatch_queue_t downloadQueue = dispatch_queue_create("ThumbnailDownloader", NULL);
dispatch_async(downloadQueue, ^{
NSURL *photoUrl = [FlickrFetcher urlForPhoto:flickrAnnotation.photo format:FlickrPhotoFormatSquare];
dispatch_async(dispatch_get_main_queue(), ^{ // execute on the main thread
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
});
});
dispatch_release(downloadQueue);
}
return image;
}
Однако с этим кодом миниатюра не отображается. Я знаю, что это потому, что когда метод «возвращает изображение», изображение по-прежнему равно нулю, потому что поток downloadQueue не завершен. Я попытался «вернуть изображение» внутри блока следующим образом:
return [UIImage imageWithData:[NSData dataWithContentsOfURL:photoUrl]];
но компилятору это не нравится:
Несовместимые типы указателей блоков, передающие «UIImage * (^) (void)» в параметр типа «disptach_block_t» (он же «void (^) (void)»)
Я знаю, что ^{ в начале блока означает пустоту, но можно ли изменить его, чтобы он возвращал UIImage? Или я изначально неправильно делаю?
Я просто не знаю, как вернуть изображение из PhotoListTableViewController обратно в MapViewController. Как это сделать?