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

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

问题描述

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

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(用于Playgrounds或直接在应用程序中使用的IE)调用authorize方法.此authorize方法将依次调用buildPOSTTask,这将构造一个有效的URL并返回一个URLSessionUploadTaskauthorize方法使用.

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:

错误域= NSURLErrorDomain代码= -999已取消" UserInfo = {NSErrorFailingURLKey =

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:参数都不能为nil.尽管该参数已标记为可选的Data,但缺少该参数后会立即被取消.这可能是苹果方面的错误,当我无法正常工作时,我打开了一个错误,因此我将使用这些新信息更新错误报告.

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方法,以解决传递的字典为nil的可能性.有了它,它现在可以正常工作:

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天全站免登陆