NSOperation 的对象在执行后不会从 NSOperationQueue 中删除
object of NSOperation doesn't removed from NSOperationQueue after executing
在我的 NSOperation 子类中,我设置了 4 个标志,当一个操作完成执行时,它不会被删除到 NSOperation 队列中,它是在开始时添加的,这在我的应用程序中引起了很多问题。
我想我设置这些标志的方式不正确,请你帮忙解决一下。因为我真的花了很多时间来确定这个问题。
@property(assign, nonatomic) BOOL isCancelled;
@property(nonatomic, getter=isExecuting) BOOL executing;
@property(nonatomic, getter=isFinished) BOOL finished;
@property(readonly, getter=isAsynchronous) BOOL asynchronous;
//in initialisation
- (id)initWithURL:(NSURL*)url andRaw:(NSInteger)row
{
if (![super init])
return nil;
[self setTargetURL:url];
return self;
}
//the way I override KVO
- (BOOL)isExecuting
{
NSLog(@"Exec");
return (self.defaultSession != nil);//it doesn't work
}
- (BOOL)isFinished
{
NSLog(@"Finished");
return (self.defaultSession == nil); //it doesn't work, so I explicitly set the value
}
- (BOOL)isAsynchronous
{
return YES;
}
- (void)cancel
{
[super cancel];
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.isExecuting = NO;
self.isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
if(self.downloadTask.state == NSURLSessionTaskStateRunning)
[self.downloadTask cancel];
[self finish];
}
- (void)finish
{
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.defaultSession = nil; //NSURLSession
self.isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
提前致谢
编辑:
最后我发现了问题 - 这是队列中的 NSURLSession 。它保持对队列的强引用,不允许它从 NSOperationQueue 中释放和删除。
我做过完全相同的事情,只是在 Swift 中。
有几个方面我实现了不同,如下所列:
- 我注意到我们不必在
异步操作。 NSOperation 取消的默认行为
方法是将 self.cancelled 布尔值设置为 true。
- self.executing 应该只在覆盖的 start() 操作方法中设置为 true,而不是在 init 中(不确定这是否会导致任何问题)。此外,在 start() 方法中设置 self.executing = true 之前,我确保布尔值 self.cancelled 为 false。如果 self.cancelled = true,我们应该设置 self.finished = true.
- 此外,我还为 isExecuting 和 isFinished 属性创建了一个 "didSet" 属性 观察器,我在其中调用 willChangeValueForKey 和 didChangeValueForKey。我不是 100% 确定如何在 Obj C 中复制 didSet 行为。(This 说要覆盖 setter)
请参阅关于 "Concurrency" 的 Ray Wenderlich 视频教程,其中 Sam DAvies 解释了为异步操作创建 NSoperation 子类。请注意,它仅适用于订阅者,并在 Swift 中进行了解释。我相信如果您修复第 1 点和第 2 点,您应该会看到您的问题得到解决。
在我的 NSOperation 子类中,我设置了 4 个标志,当一个操作完成执行时,它不会被删除到 NSOperation 队列中,它是在开始时添加的,这在我的应用程序中引起了很多问题。 我想我设置这些标志的方式不正确,请你帮忙解决一下。因为我真的花了很多时间来确定这个问题。
@property(assign, nonatomic) BOOL isCancelled;
@property(nonatomic, getter=isExecuting) BOOL executing;
@property(nonatomic, getter=isFinished) BOOL finished;
@property(readonly, getter=isAsynchronous) BOOL asynchronous;
//in initialisation
- (id)initWithURL:(NSURL*)url andRaw:(NSInteger)row
{
if (![super init])
return nil;
[self setTargetURL:url];
return self;
}
//the way I override KVO
- (BOOL)isExecuting
{
NSLog(@"Exec");
return (self.defaultSession != nil);//it doesn't work
}
- (BOOL)isFinished
{
NSLog(@"Finished");
return (self.defaultSession == nil); //it doesn't work, so I explicitly set the value
}
- (BOOL)isAsynchronous
{
return YES;
}
- (void)cancel
{
[super cancel];
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.isExecuting = NO;
self.isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
if(self.downloadTask.state == NSURLSessionTaskStateRunning)
[self.downloadTask cancel];
[self finish];
}
- (void)finish
{
[self willChangeValueForKey:@"isExecuting"];
[self willChangeValueForKey:@"isFinished"];
self.defaultSession = nil; //NSURLSession
self.isFinished = YES;
[self didChangeValueForKey:@"isFinished"];
[self didChangeValueForKey:@"isExecuting"];
}
提前致谢
编辑: 最后我发现了问题 - 这是队列中的 NSURLSession 。它保持对队列的强引用,不允许它从 NSOperationQueue 中释放和删除。
我做过完全相同的事情,只是在 Swift 中。
有几个方面我实现了不同,如下所列:
- 我注意到我们不必在 异步操作。 NSOperation 取消的默认行为 方法是将 self.cancelled 布尔值设置为 true。
- self.executing 应该只在覆盖的 start() 操作方法中设置为 true,而不是在 init 中(不确定这是否会导致任何问题)。此外,在 start() 方法中设置 self.executing = true 之前,我确保布尔值 self.cancelled 为 false。如果 self.cancelled = true,我们应该设置 self.finished = true.
- 此外,我还为 isExecuting 和 isFinished 属性创建了一个 "didSet" 属性 观察器,我在其中调用 willChangeValueForKey 和 didChangeValueForKey。我不是 100% 确定如何在 Obj C 中复制 didSet 行为。(This 说要覆盖 setter)
请参阅关于 "Concurrency" 的 Ray Wenderlich 视频教程,其中 Sam DAvies 解释了为异步操作创建 NSoperation 子类。请注意,它仅适用于订阅者,并在 Swift 中进行了解释。我相信如果您修复第 1 点和第 2 点,您应该会看到您的问题得到解决。