URLSessionUploadTask 立即自动取消 [英] URLSessionUploadTask getting automatically cancelled instantly

查看:37
本文介绍了URLSessionUploadTask 立即自动取消的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个奇怪的问题,即新创建的 URLSessionUploadTask 立即被取消.我不确定这是否是 Xcode 8 当前测试版的错误.

I'm having this weird issue in which a newly created URLSessionUploadTask gets cancelled instantly. I'm not sure if it's a bug with the current beta of Xcode 8.

我怀疑这可能是一个错误,因为我即将发布的代码恰好运行了一次.之后没有对其进行任何更改,然后它只是停止工作.是的,它确实运行了一次,然后就停止工作了.我会在接近尾声时发布错误.

I suspect it might be a bug because the code I'm about to post ran fine exactly once. No changes were made to it afterwards and then it simply stopped working. Yes, it literally ran once, and then it stopped working. I will post the error near the end.

我将在下面发布代码,但首先我将总结这里的逻辑是如何工作的.

I will post the code below, but first I will summarize how the logic here works.

我的测试或用户公开的 API(IE 用于 Playgrounds 或直接用于应用程序)调用 authorize 方法.这个 authorize 方法将依次调用 buildPOSTTask,后者将构造一个有效的 URL 并返回一个 URLSessionUploadTaskauthorize<使用/code> 方法.

My test, or user-exposed API (IE for use in Playgrounds or directly on apps), calls the authorize method. This authorize method will in turn call buildPOSTTask, which will construct a valid URL and return a URLSessionUploadTask to be used by the authorize method.

话虽如此,代码如下:

会议:

internal let urlSession = URLSession(configuration: .default)

创建上传任务的函数:

internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
    let fullURL: URL
    if let gets = getParams {
        fullURL = buildURL(appendingPath: path, withGetParameters: gets)
    } else {
        fullURL = URL(string: path, relativeTo: baseURL)!
    }

    var request = URLRequest(url: fullURL)
    request.httpMethod = "POST"

    var postParameters: Data? = nil

    if let posts = postParams {
        do {
            postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
        } catch let error as NSError {
            fatalError("[(#function) (#line)]: Could not build POST task: (error.localizedDescription)")
        }
    }

    let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
    return postTask
}

身份验证函数,它使用上述函数创建的任务:

The authentication function, which uses a task created by the above function:

    public func authorize(withCode code: String?, completion: AccessTokenExchangeCompletionHandler) {

// I have removed a lot of irrelevant code here, such as the dictionary building code, to make this snippet shorter.

        let obtainTokenTask = buildPOSTTask(onURLSession: self.urlSession, appendingPath: "auth/access_token", withPostParameters: nil, getParameters: body, httpHeaders: nil) { (data, response, error) in
            if let err = error {
                completion(error: err)
            } else {
                print("Response is (response)")
                completion(error: nil)
            }
        }

        obtainTokenTask.resume()
    }

我在测试中发现了这个错误:

I caught this error in a test:

let testUser = Anilist(grantType: grant, name: "Test Session")

let exp = expectation(withDescription: "Waiting for authorization")

testUser.authorize(withCode: "a valid code") { (error) in
    if let er = error {
        XCTFail("Authentication error: (er.localizedDescription)")
    }
    exp.fulfill()
}
self.waitForExpectations(withTimeout: 5) { (err) in
    if let error = err {
        XCTFail(error.localizedDescription)
    }
}

它总是立即失败并出现此错误:

It always fails instantly with this error:

Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&ibanclient_id=hod6w&code=REMOVED,NSLocalizedDescription=取消,NSErrorFailingURLStringKey=

Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED, NSLocalizedDescription=cancelled, NSErrorFailingURLStringKey=https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED}

请记住以下几点:

  • 会话使用的 URL 有效.
  • 所有凭据均有效.
  • 立即失败并显示已取消"错误,这在以前根本没有发生过.我没有在任何地方取消任务,所以它被系统取消了.
  • 在启用无限期执行的 Playgrounds 上也会失败.这不仅限于我的测试.
  • The URL used by the session is valid.
  • All credentials are valid.
  • It fails instantly with a "cancelled" error, that simply did not happen before. I am not cancelling the task anywhere, so it's being cancelled by the system.
  • It also fails on Playgrounds with indefinite execution enabled. This is not limited to my tests.

这是我尝试过的事情的列表:

Here's a list of things I have tried:

  • 因为我怀疑这是一个错误,所以我首先尝试清理我的项目、删除派生数据并重置所有模拟器.他们都没有工作.
  • 甚至重新启动我的 Mac...
  • 在怀疑上传任务由于没有任何强指针而被解除分配的情况下,又调用了cancel,我也重写了authorize 以返回buildPOSTTask 创建的任务并将其分配给我的测试中的一个变量.任务仍然被取消.
  • Because I suspect this is a bug, I first tried to clean my project, delete derived data, and reset all simulators. None of them worked.
  • Even went as far restarting my Mac...
  • Under the small suspicion that the upload task was getting deallocated due to it not having any strong pointers, and in turn calling cancel, I also rewrote authorize to return the task created by buildPOSTTask and assigned it to a variable in my test. The task was still getting cancelled.

我还没有尝试过的事情(但我会接受任何其他想法,因为我正在处理这些):

Things I have yet to try (but I will accept any other ideas as I work through these):

  • 在物理设备上运行它.目前正在 iPad 上下载 iOS 10,因为这是一个 iOS 10 项目.我刚刚尝试过,但这是不可能的.

我不知道该尝试什么.生成的日志似乎没有任何有用的信息.

I'm out of ideas of what to try. The generated logs don't seem to have any useful info.

我决定在这里发布整个项目.无论如何,当它完成时,这件事将是开源的,而我获得的 API 凭据是用于测试应用程序的.

I have decided to just post the entire project here. The thing will be open source anyway when it is finished, and the API credentials I got are for a test app.

ALCKit

推荐答案

经过 6 天不停地为此苦苦挣扎,并在不停地搜索解决方案后,我真的很高兴说我终于想通了.

After struggling non-stop with this for 6 days, and after googling non-stop for a solution, I'm really happy to say I have finally figured it out.

事实证明,无论出于什么神秘原因,uploadTask(with:from:completionHandler) 中的 from: 参数不能为零.尽管该参数被标记为可选的 Data,但当它丢失时它会立即被取消.这可能是 Apple 方面的一个错误,当我无法让它工作时,我打开了一个错误,所以我会用这个新信息更新我的错误报告.

Turns out that, for whatever mysterious reason, the from: parameter in uploadTask(with:from:completionHandler) cannot be nil. Despite the fact that the parameter is marked as an optional Data, it gets cancelled instantly when it is missing. This is probably a bug on Apple's side, and I opened a bug when I couldn't get this to work, so I will update my bug report with this new information.

话虽如此,我所要做的就是更新我的 buildPOSTTask 方法,以解决传递的字典为零的可能性.有了它,它现在可以正常工作了:

With that said, everything I had to do was to update my buildPOSTTask method to account for the possibility of the passed dictionary to be nil. With that in place, it works fine now:

internal func buildPOSTTask(onURLSession urlSession: URLSession, appendingPath path: String, withPostParameters postParams: [String : String]?, getParameters getParams: [String : String]?, httpHeaders: [String : String]?, completionHandler completion: URLSessionUploadTaskCompletionHandler) -> URLSessionUploadTask {
    let fullURL: URL
    if let gets = getParams {
        fullURL = buildURL(appendingPath: path, withGetParameters: gets)
    } else {
        fullURL = URL(string: path, relativeTo: baseURL)!
    }

    var request = URLRequest(url: fullURL)
    request.httpMethod = "POST"

    var postParameters: Data

    if let posts = postParams {
        do {
            postParameters = try JSONSerialization.data(withJSONObject: posts, options: [])
        } catch let error as NSError {
            fatalError("[(#function) (#line)]: Could not build POST task: (error.localizedDescription)")
        }
    } else {
        postParameters = Data()
    }

    let postTask = urlSession.uploadTask(with: request, from: postParameters, completionHandler: completion)
    return postTask
}

这篇关于URLSessionUploadTask 立即自动取消的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆