【问题标题】:delegate deallocated during the operation在操作期间解除分配的委托
【发布时间】:2014-04-07 09:31:23
【问题描述】:

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

我有一个在后台下载图像的 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,它正在尝试处理响应......当然我得到了消息发送到 deallocated...

我在CachedImageView中alloc初始化这样的操作:

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

或:

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

【问题讨论】:

  • 将assign属性替换为weak
  • 我没用ARC,所以不能用weak
  • 有很多框架可以异步加载图片。以 SDWebImage 为例。
  • weak 和 assign 是相同的,在 ARC 项目中使用 weak 但它们的数量相同。您的协议声明在哪里?
  • 我用协议声明更新了我的问题

标签: ios memory-management delegates nsoperation dealloc


【解决方案1】:

问题是:当我转到另一个页面时,图像是 下载,缓存的ImageView被释放

处理这个问题的通常方法是在 CachedImageView 的 dealloc 中将自己作为委托移除。喜欢

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

【讨论】:

    【解决方案2】:

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

    @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 &amp;&amp; [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];
    

    【讨论】:

    • 我正在做同样的事情。问题是在图像视图被解除分配后,委托仍然不是零,并且操作试图调用 handleResponse 方法,我收到消息发送到解除分配
    • 这不是它崩溃的原因,如果委托不是 nil 但没有任何东西可以响应选择器,如果它不会进入。还有其他事情在起作用。
    • 我用 更新了我的代码。但是如果imageView是dealloc,它仍然会崩溃,并且图像没有下载。我更新了我的问题
    • 谢谢。它对我有帮助
    【解决方案3】:

    编写代码的更好方法是:

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

    这将避免您的崩溃。

    【讨论】:

    • 这并没有解决我的问题。它在responsToSelector 处崩溃。见上图
    • 查看上面的帖子。您必须首先在 dealloc 方法中将委托设置为 nil。否则,无论您检查什么,应用都会崩溃。
    【解决方案4】:

    我已经解决了这个问题,我使用了 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被释放,它的delegate将为nil,并且不会随时崩溃)

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

    【讨论】:

    • 这基本上就是我所说的,如果对您有帮助,请将我的答案标记为正确。
    猜你喜欢
    • 2013-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-13
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多