代表在行动期间解除分配

时间:2014-04-07 09:31:24

标签: ios memory-management delegates nsoperation dealloc

我正在寻找解决以下问题的解决方案:

我有一个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完成下载时,委托不是nil,并且它正在尝试处理响应...并且当然我把消息发送到解除分配...

我在CachedImageView:

中分配init这样的操作
CoreImageDownloadingOperation* imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];

enter image description here 或者:

enter image description here

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

4 个答案:

答案 0 :(得分:1)

  

问题是:当我转到另一页时图像是   下载时,cachedImageView被解除分配

处理此问题的常用方法是将自身作为CachedImageView的dealloc中的委托删除。像

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

答案 1 :(得分:0)

编写代码的更好方法是:

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

这可以避免您的崩溃。

答案 2 :(得分:0)

您的协议声明在哪里?我希望看到这个:

@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&amp;&amp;如果没有实现选择器。

编辑 *

您创建的位置:

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];

答案 3 :(得分:0)

我已经解决了这个问题,我使用了CW0007007解决方案和我自己的解决方案。所以我把我的操作变成了一个保留的属性:

@property (nonatomic, retain) CoreImageDownloadingOperation* imageDownloadingOperation;

之后我检查了手术是否还活着

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

然后添加到操作队列。

在dealloc中将委托设置为nil(仅在操作处于活动状态时为ofc),然后释放它:

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

在操作中:(现在如果imageView被解除分配,其委托将为零,并且随时都会崩溃)

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