Делегат освобожден во время операции

Я ищу решение, которое решает следующую проблему:

У меня есть NSOperation, который загружает изображение в фоновом режиме:

@protocol CoreImageDownloadingOperationDelegate <NSObject>

@required
-(void) handleResponse:(UIImage*) response;
-(void) handleException:(MobileServiceException*) exception;

@end

@interface CoreImageDownloadingOperation : NSOperation{
}

-(id) initWithDelegate:(id<CoreImageDownloadingOperationDelegate>)del andImageID: (NSString *) image;

@property (nonatomic, assign) id <CoreImageDownloadingOperationDelegate> delegate;

Когда закончится загрузка, вызывается метод делегата, чтобы установить изображение в imageView:

pragma mark - overridden from NSOperation
- (void) main {

    if (self.isCancelled)
        return;

    @autoreleasepool {

        @try {

            UIImage* image = [[CoreEnvironment sharedInstance] getImageFromServer: [imageID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];

            if (self.isCancelled)
                return;

            if(delegate){
                [delegate handleResponse:image];
            }
            else
                NSLog(@"CachedImageView already deallocated");

        }@catch (NSException *exception) {

            TestLog(@"%@", exception.reason);

            if (self.isCancelled)
                return;

            if(delegate && [exception isKindOfClass:[MobileServiceException class]])
                [delegate handleException:(MobileServiceException*)exception];

        }
    }
}

Проблема заключается в том, что когда я перехожу на другую страницу во время загрузки изображения, объект cachedImageView освобождается, но когда загрузка imageDownloadingOperation завершает загрузку, делегат не равен нулю, и он пытается обработать ответ... И, конечно, я получаю сообщение, отправленное на перераспределена...

Я выделяю init операцию, как это в CachedImageView:

CoreImageDownloadingOperation* imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];

введите описание изображения здесьили же:

введите описание изображения здесь

-[CachedImageView isKindOfClass:]: message sent to deallocated instance 0x18868550

4 ответа

Решение

Где ваша декларация протокола? Я ожидаю увидеть это:

@protocol CoreImageDownloadingOperationDelegate <NSObject> 

- (void) handleResponse:(UIImage *) image;

@end

@interface CoreImageDownloadingOperation : NSOperation{
}

-(id) initWithDelegate:(id<CoreImageDownloadingOperationDelegate>)del andImageID: (NSString *) image;

@property (nonatomic, assign) id <CoreImageDownloadingOperationDelegate> delegate;

Вы получаете предупреждение / сбой, потому что он не может найти ответчика handleResponse:

Также при вызове делегата вам лучше делать:

if ([self.delegate respondsToSelector:@selector(handleResponse:)])
    [self.delegate handleResponse:image];

Вам не нужно проверять if (self.delegate && [self.delegate responds .... так как он вернет nil, если делегат равен nil &&, если селектор не реализован.

РЕДАКТИРОВАТЬ *

Где вы создаете:

CoreImageDownloadingOperation* imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];

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

В твоем.h

@property (nonatomic, retain) CoreImageDownloadingOperation* imageDownloadingOperation;

Затем инициализируйте с помощью:

if (!self.imageDownloadingOperation)
    self.imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];

Проблема в том, что когда я перехожу на другую страницу во время загрузки изображения, cachedImageView освобождается

Обычный способ справиться с этим - удалить себя в качестве делегата в dealloc CachedImageView. подобно

// in CachedImageView
- (void)dealloc {
  // CachedImageView keeps a reference to the operation
  // called imageDownloadingOperation
  imageDownloadingOperation.delegate = nil;
  [super dealloc];
}

Лучший способ написания кода:

 if([self.delegate respondsToSelector:@selector(handleResponse:)){
    [self.delegate handleResponse:image];
}

Это поможет избежать аварии.

Я решил проблему, я использовал решение CW0007007 и мое собственное решение. Поэтому я превратил свою операцию в оставшуюся собственность:

@property (nonatomic, retain) CoreImageDownloadingOperation* imageDownloadingOperation;

после этого я проверил, жива ли операция

if (!imageDownloadingOperation)
        imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];

затем добавляется в очередь операций.

В dealloc установите делегата на ноль (ofc, только если операция жива) и отпустите его:

if (imageDownloadingOperation) {
    imageDownloadingOperation.delegate = nil;
    [imageDownloadingOperation release];
}

в операции: (и теперь, если imageView освобожден, его делегат будет равен нулю и не будет аварийно завершаться в любое время)

if (delegate)        
    if ([delegate respondsToSelector:@selector(handleResponse:)])
        [delegate handleResponse:image];
Другие вопросы по тегам