iOS (cs193p): проблема с использованием делегата в MapViewController для получения изображения с использованием другого потока из другого контроллера.

Я читаю прекрасную лекцию 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. Как это сделать?


person Pascal    schedule 25.01.2013    source источник


Ответы (1)


Я работаю над тем же заданием. Я переключал потоки, когда вызывался делегат контроллера табличного представления, вместо того, чтобы ждать, пока контроллер табличного представления извлечет изображение, и это работает для меня.

В коде:

-(void)mapView:(MKMapView *)mapView didSelectAnnotationView:(MKAnnotationView *)view { // NSLog(@"Выбрана аннотация, получена миниатюра");

dispatch_queue_t downloadQueue = dispatch_queue_create("flickr download", NULL);
dispatch_async(downloadQueue, ^{
    UIImage *image = [self.delegate thumbNailImageForAnnotation:view.annotation sender: self];

    dispatch_async(dispatch_get_main_queue(), ^{

        [(UIImageView *)view.leftCalloutAccessoryView setImage:image];

    });

});

}

person ChipK    schedule 26.01.2013
comment
Блестящий! Я должен был подумать об этом... большое спасибо за помощь! Интересно, можно ли было бы сделать это по-моему... но тем не менее ваш подход мне нравится больше! - person Pascal; 27.01.2013
comment
Вы все еще проходите осенний курс 2011 г. и работаете над заданием № 5? Если хотите, мы могли бы обменяться электронными письмами (или какой-либо контактной информацией), чтобы задать друг другу вопросы и поделиться кодом. - person Pascal; 27.01.2013
comment
Да, я плетусь, также отслеживая новую сессию, которая началась на прошлой неделе, чтобы собрать советы по iOS 6, но я планирую закончить проекты для курса Fall '11. Я не работал с Git в течение нескольких лет, но сегодня вечером я попытался опубликовать свой код flickR в центре Git. Его можно найти по адресу github.com/chipk215/FlickrToy. Вы можете получить мою электронную почту там. - person ChipK; 27.01.2013
comment
То же самое здесь, я хочу следить за новыми зимними лекциями 2013 года ... но я хочу закончить лекции осени 2011 года раньше, так как я потратил на них много часов. Мне нужно исправить несколько ошибок, а затем я также опубликую свой код на Github. Спасибо! - person Pascal; 27.01.2013