Метод делегирования не вызывается

#iphone #objective-c #delegates #nsoperation #nsoperationqueue

#iPhone #objective-c #делегаты #nsoperation #nsoperationqueue

Вопрос:

Я создаю вспомогательный класс с открытым исходным кодом (github) для асинхронной загрузки изображений (с которым у меня были серьезные проблемы).

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

Пожалуйста, взгляните на мой код! Я опубликовал только соответствующий код.

MKAsyncImageDownloader.h

 @protocol MKAsyncImageDownloaderDelegate <NSObject>
@required
- (void)imageShouldFinishDownloading;
@end
@interface MKAsyncImageDownloader : NSObject {
    id <MKAsyncImageDownloaderDelegate> delegate;
}
- (id) initWithDelegate:(id <MKAsyncImageDownloaderDelegate>) delegat;
@property (retain, nonatomic) id <MKAsyncImageDownloaderDelegate> delegate;
@end
  

MKAsyncImageDownloader.m

 - (id) initWithDelegate:(id<MKAsyncImageDownloaderDelegate>) delegat {
    self = [super init];
    if (self) {
        delegate = delegat;
    }
    return self;
}
- (void)imageAtURLHasDownloaded:(NSDictionary *)dict {
    [downloadedImageArray addObject:[dict objectForKey:@"image"]];
    [[self delegate] imageShouldFinishDownloading];
}
  

MKOperation.m
Подкласс NSOperation.
Я выделяю / инициализирую MKAsynImageDownloader только для выполнения селектора.
Код:

 - (void)start {
    UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:self.targetURL]];
    if (image) {
        NSDictionary *dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:image, self.targetURL, nil] forKeys:[NSArray arrayWithObjects:@"image", @"url", nil]];
        MKAsyncImageDownloader *downloader = [[MKAsyncImageDownloader alloc] init];
        [downloader performSelectorOnMainThread:@selector(imageAtURLHasDownloaded:) withObject:dict waitUntilDone:YES];
        [dict release];
        [downloader release];
     }
    [image release];
}
  

RootViewController.h

 MKAsyncImageDownloader *loader;
  

RootViewController.m
Просто чтобы показать, как я настраиваю делегат.

  loader = [[MKAsyncImageDownloader alloc] initWithDelegate:self];
  

Комментарии:

1. Не имеет прямого отношения к вашей проблеме, но ваше свойство сохраняет делегат, но ваш init назначает. Как правило, «назначить» является правильным ответом при работе с делегатами.

2. Наконец, поставьте точку останова в imageAtURLHasDownloaded, и я не могу представить, что было бы так сложно найти проблему…

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

Ответ №1:

В вашем start методе вы никогда не вызываете свой собственный метод инициализации, вы вызываете:

 MKAsyncImageDownloader *downloader = [[MKAsyncImageDownloader alloc] init];
  

вы должны вызывать

 MKAsyncImageDownloader *downloader = [[MKAsyncImageDownloader alloc] initWithDelegate:myDelegate];
  

Тогда вы говорите, что установили loader объект где-то еще? Это два отдельных объекта, тот, который вы, похоже, на самом деле используете, — это то, на что ссылается выше.

Это:

 loader = [[MKAsyncImageDownloader alloc] initWithDelegate:self];
  

не создает

 MKAsyncImageDownloader *downloader = [[MKAsyncImageDownloader alloc] init];
  

работает. Ваша MKOperation не имеет ссылки на ваш loader класс, в котором установлен делегат.

Вы заявляете:

MKOperation.m Подкласс NSOperation. Я выделяю / инициализирую MKAsynImageDownloader только для выполнения селектора.

Я думаю, вы неправильно понимаете, что вы здесь делаете. Вы создаете совершенно новый экземпляр MKAsynImageDownloader и выполняете селектор для этого экземпляра, а не для loader экземпляра, который находится в вашем RootController. Вероятно, вы хотите MKOperation взять MKAsyncImageDownloader объект во время его инициализации.

Редактировать:

Это «загрузчик», о котором я говорю. В начале вашей mkoperation’s start

 if (image) {
    NSDictionary *dict = [[NSDictionary alloc] initWithObjects:[NSArray arrayWithObjects:image, self.targetURL, nil] forKeys:[NSArray arrayWithObjects:@"image", @"url", nil]];
    -->> MKAsyncImageDownloader *downloader = [[MKAsyncImageDownloader alloc] init];
    [downloader performSelectorOnMainThread:@selector(imageAtURLHasDownloaded:) withObject:dict waitUntilDone:YES];
    [dict release];
    [downloader release];
 }
  

Это отдельный экземпляр от того, который находится в вашем RootViewController, у этого нет набора делегатов. ЭТО тот, над которым вы работаете, следовательно, именно этот пытается уведомить делегата… но опять же, у него нет набора делегатов.

Комментарии:

1. Однако MKOperation, подклассу NSOperation, не обязательно быть делегатом. Ничего не нужно менять в файле MKOperation, когда он загрузил изображение. RootViewController — это единственный класс, который необходимо установить в качестве делегата.

2. Но MKOperation — это то, где выполняется работа! Вы создаете другой экземпляр, у этого экземпляра нет набора делегатов.

3. метод делегирования вызывается в MKOperation, но мне нужно, чтобы он вызывался в RootViewController, поскольку TableView необходимо обновить.

4. загрузчик!= downloader, я не знаю, что еще тебе сказать.

5. loader.class != downloader.class !!! загрузчик находится в файле RootViewController.h, а загрузчик — в подклассе MKOperation, NSOperation.

Ответ №2:

Вы заглядывали в SDWebImage?

Иногда самый простой способ решить проблему — использовать рабочий код, который вам не нужно поддерживать…

https://github.com/rs/SDWebImage