NSOperationQueue XXXX isFinished=YES without being started by the queue it is in

本文介绍了在iOS开发中遇到的一个关于NSOperationQueue的异常问题,当用户暂停队列中的任务时,系统抛出'isFinished=YES without being started by the queue it is in'的错误。分析了问题产生的原因,强调了在Queue中操作的正确管理方式,包括重写start方法以处理取消操作的情况,并提供了一种解决方案,通过添加标志位 '_hasStart' 来确保KVO的正确使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚入职公司,负责iOS组的全部工作,同事就给我找了一个难啃的BUG,如题:XXXX isFinished=YES without being started by the queue it is in


问题研究:

1、为何造成 Queue里的operation 先于start方法执行了 isFinished=YES


a、项目有文件上传下载队列需求

b、对线程执行要求并发

c、设置的最大并发量是2


场景:用户上传3个文件 123

问题出来了:Queue队列里 12正在执行,3正在等待,此时用户暂停正在排队的3,一定出现 XXXX isFinished=YES without being started by the queue it is in 的系统异常信息

此时,用户点击3继续下载,崩溃


2、这个异常operationQueue中到底是个什么存在


这个operationQueue中正在等待,绝对不允许对他的状态做任何改变!!绝对不允许对他的状态做任何改变!!绝对不允许对他的状态做任何改变!!


这里指的是isFinished关联的状态 KVO绝对不能在未执行start方法之前就改动

 

3、正确管理operation的姿势应该是怎样的?



a、一定要重写start方法,why ?



 经我跟小组同事研究得出系统执行start的大致过程:在start里判断当前operation是否已经取消(isCanceled)? 若取消,则不再执行Main方法,并且不会将isFinished置为YES,因为此时isFinished已经被重写 


  因此自定义NSOperation ,如果不重写start方法,就会发生一个情况:我们将3 cancel掉,然后1、2执行完毕,整个Queue就一直卡在3,整个Queue就无效了


2、加一个标志位: _hasStart 

     用于确定是否该给operation及时的设置isFinished的KVO !!!



最后附关键代码:



-(void)start

{  

    _hasStart = YES;


    // Always check for cancellation before launching the task.

    if ([self isCancelled])

    {

        // Must move the operation to the finished state if it is canceled.

        [self willChangeValueForKey:@"isFinished"];

        _operationFinished = YES;

        [self didChangeValueForKey:@"isFinished"];

        

        //内存清空

        [self finishOperation];

        

        return;

    }

    

    // If the operation is not canceled, begin executing the task.

    [self willChangeValueForKey:@"isExecuting"]; 

    [NSThread detachNewThreadSelector:@selector(main)

                             toTarget:self withObject:nil];

    _operationExecuting = YES; 

    [self didChangeValueForKey:@"isExecuting"];

}


- (void)main

{

    NSLog(@"QFOperation main");

    

    // 在异步线程调用就不能够访问主线程的自动释放池

    // 因此在这里新建一个属于当前线程的自动释放池

    @autoreleasepool

    {

        [self startUpload]; // 开始准备上传

    }

}















评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值