【问题标题】:How to immediately force cancel an NSOperation with AFNetworking?如何使用 AFNetworking 立即强制取消 NSOperation?
【发布时间】:2012-09-11 02:12:53
【问题描述】:

我正在我的应用程序中使用 AFNetworking,并且我正在尝试在我的进度 HUD 中实现“点击取消”功能。我有一个管理所有 HTTP 请求的单例类。如果点击进度HUD,我会调用:

[[[HTTPRequestSingleton sharedClient] operationQueue] cancelAllOperations];

但这不会像我需要的那样“取消”操作。我阅读了NSOperationQueue docs 并遇到了这个:

取消操作对象会使对象留在队列中,但会通知对象它应该尽快中止其任务。对于当前正在执行的操作,这意味着操作对象的工作代码必须检查取消状态,停止正在执行的操作,并将自身标记为已完成。对于已排队但尚未执行的操作,队列仍必须调用操作对象的 start 方法,以便它可以处理取消事件并将自己标记为已完成。

关于cancelAllOperations 方法:

此方法向当前队列中的所有操作发送取消消息。排队的操作在开始执行之前被取消。如果某个操作已经在执行,则由该操作来识别取消并停止它正在执行的操作。

我的问题似乎特别涉及已经执行的操作,我想立即取消它。使用 AFNetworking,我如何提醒操作它应该取消并丢弃有关请求的所有信息?

用于操作的代码

AFJSONRequestOperation *loginOperation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {

    //operation was successful

    if (loginOperation.isCancelled)
    {
        //can't do this. variable 'loginOperation' is uninitialized when captured by block      
    }

} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON) {

    //operation failed

}];

【问题讨论】:

  • 操作没有立即终止到底是什么问题?
  • 操作照常继续,success: 块被调用。如果操作被取消,我想找到一种方法来禁止调用该块。
  • 顺便说一句:您可以使用 NSError 实例检查请求是否由于回调中的取消而失败,如下所示:[错误代码] == NSURLErrorCancelled。

标签: objective-c cocoa-touch nsoperation afnetworking


【解决方案1】:

经过一上午的 AFNetworking 源代码挖掘后,发现我的操作没有取消的原因与操作本身无关,而是因为我一直在错误地启动操作。我一直在用

[NSOperation start];

当我应该将它添加到我的 HTTPRequestSingleton 的操作队列时:

[[[HTTPRequestSingleton sharedClient] operationQueue] addOperation:NSOperation];

将它添加到队列允许它被正确取消而无需检查isCancelled 属性。

【讨论】:

    【解决方案2】:

    完成块

    当操作的 main 时返回要执行的块 任务完成。

    • (void (^)(void))completionBlock 返回值 操作的主要任务完成后要执行的块。这个块不需要 参数并且没有返回值。

    讨论你提供的完成块在值的时候执行 isFinished 方法返回的更改为 YES。因此,这个块是 在操作的主要任务之后由操作对象执行 已完成或取消

    查看操作isCancelled属性,了解为什么会调用回调。


    查看初始化代码:

    + (AFJSONRequestOperation *)JSONRequestOperationWithRequest:(NSURLRequest *)urlRequest
                                                        success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON))success 
                                                        failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error, id JSON))failure
    {
        AFJSONRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease];
        [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            if (success) {
                success(operation.request, operation.response, responseObject);
            }
        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
            if (failure) {
                failure(operation.request, operation.response, error, [(AFJSONRequestOperation *)operation responseJSON]);
            }
        }];
        
        return requestOperation;
    }
    

    要在回调中获取operation var,您需要在JSONRequestOperationWithRequest:success:failure: 初始化之后使用setCompletionBlockWithSuccess,这有点矫枉过正,更好的方法是复制代码并使用

        AFJSONRequestOperation *requestOperation = [[[self alloc] initWithRequest:urlRequest] autorelease];
        [requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    
        // ... here you can check `isCancelled` flag
    

    【讨论】:

    • 好的,很高兴了解isCancelled 属性,但是如何从success:failure: 回调块中检查该值?或者最好使用该值来禁止到达success:failure: 块?
    • 你没有AFHTTPRequestOperation * var 作为回调参数吗?你会想检查operation.isCancelled
    • 不,AFJSONRequestOperation 的回调参数是 JSON 对象的 NSURLRequestNSHTTPURLResponseid。操作本身没有传递到块中,所以我不知道如何检查它的 isCancelled 属性。我已经添加了用于问题中操作的代码。感谢您迄今为止的帮助。
    • 查看答案更新,展示您如何使用自己的回调,并将 operation var 用作参数。
    • 非常感谢您的帮助。我的问题原来是因为我如何将NSOperation 添加到队列中,但您的回答很有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-17
    • 1970-01-01
    • 2021-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-03
    相关资源
    最近更新 更多