Делегат освобожден во время операции
Я ищу решение, которое решает следующую проблему:
У меня есть 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];