objective-c - NSOperation 中的 NSURLSessionDownloadTask 在取消时崩溃
问题描述
我正在尝试创建 NSOperation 的 DownloadOperation 子类来异步下载数据。在我尝试添加取消支持之前,一切似乎都运行良好。基本上,操作的 NSURLSessionDownloadTask 的完成处理程序似乎是在操作释放后调用的。它将在该行出现 EXC_BAD_ACCESS 崩溃weakSelf.state = kFinished
。
完整的示例项目在这里:https ://github.com/angstsmurf/DownloadOperationQueue 。按 Command+。跑到崩溃后。
#import "DownloadOperation.h"
typedef enum OperationState : NSUInteger {
kReady,
kExecuting,
kFinished
} OperationState;
@interface DownloadOperation ()
@property NSURLSessionDownloadTask *task;
@property OperationState state;
@end
@implementation DownloadOperation
// default state is ready (when the operation is created)
@synthesize state = _state;
- (void)setState:(OperationState)state {
@synchronized(self) {
if (_state != state) {
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
_state = state;
[self didChangeValueForKey: @"isExecuting"];
[self didChangeValueForKey: @"isFinished"];
}
}
}
- (OperationState)state {
@synchronized (self) {
return _state;
}
}
- (BOOL)isReady { return (self.state == kReady); }
- (BOOL)isExecuting { return (self.state == kExecuting); }
- (BOOL)isFinished { return (self.state == kFinished); }
- (BOOL)isAsynchronous {
return YES;
}
- (instancetype)initWithSession:(NSURLSession *)session downloadTaskURL:(NSURL *)downloadTaskURL completionHandler:(nullable void (^)(NSURL * _Nullable, NSURLResponse * _Nullable, NSError * _Nullable))completionHandler {
self = [super init];
if (self) {
__unsafe_unretained DownloadOperation *weakSelf = self;
// use weak self to prevent retain cycle
_task = [[NSURLSession sharedSession] downloadTaskWithURL:downloadTaskURL
completionHandler:^(NSURL * _Nullable localURL, NSURLResponse * _Nullable response, NSError * _Nullable error) {
/*
if there is a custom completionHandler defined,
pass the result gotten in downloadTask's completionHandler to the
custom completionHandler
*/
if (completionHandler) {
completionHandler(localURL, response, error);
}
/*
set the operation state to finished once
the download task is completed or have error
*/
weakSelf.state = kFinished;
}];
}
return self;
}
- (void)start {
/*
if the operation or queue got cancelled even
before the operation has started, set the
operation state to finished and return
*/
if (self.cancelled) {
self.state = kFinished;
return;
}
// set the state to executing
self.state = kExecuting;
NSLog(@"downloading %@", self.task.originalRequest.URL.absoluteString);
// start the downloading
[self.task resume];
}
-(void)cancel {
[super cancel];
// cancel the downloading
[self.task cancel];
}
@end
解决方案
正如 Scott Thompson 在评论中指出的那样,用于 weakSelf 变量的正确关键字是__weak
, not __unsafe_unretained
。
推荐阅读
- javascript - UseEffect API 请求未在页面加载时显示
- python - 应用自定义方法时,切片子类化熊猫系列返回完整数据
- python - 词形还原后如何获得单词的后缀(Python)?
- r - 如何使用预定义的级别剪切两个 Posixct 序列
- python - 我不明白这两行代码之间的区别以及它们为什么返回不同的结果
- git - Git如何压缩所有提交
- javascript - 为什么不比较就返回false?
- python - 使用 Pyspark df.select() 堆叠输出
- java - 使用父类型和子类型参数重载方法并在调用时传递 null。为什么调用带有子类型参数的方法
- sql - Oracle - 无法在“目标:”运行列表中查看包内的所有过程