11

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

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

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

我的测试或用户公开的 API(用于 Playgrounds 或直接在应用程序上使用的 IE)调用该authorize方法。该authorize方法将依次调用buildPOSTTask,它将构造一个有效的 URL 并返回一个URLSessionUploadTask供该authorize方法使用的。

话虽如此,代码如下:

会议:

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
}

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

    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()
    }

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

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)
    }
}

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

错误域=NSURLErrorDomain 代码=-999 “取消” UserInfo={NSErrorFailingURLKey= https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldtexist.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=genericwebsitethatshouldtexist.bo&client_id=ibanez-hod6w&code=REMOVED }

这里有几件事要记住:

  • 会话使用的 URL 有效。
  • 所有凭据均有效。
  • 它立即失败并出现“取消”错误,这在以前根本没有发生过。我没有在任何地方取消任务,所以它被系统取消了。
  • 在启用了无限期执行的 Playgrounds 上,它也会失败。这不仅限于我的测试。

这是我尝试过的事情的清单:

  • 因为我怀疑这是一个错误,所以我首先尝试清理我的项目,删除派生数据,并重置所有模拟器。他们都没有工作。
  • 甚至重新启动我的Mac...
  • 怀疑上传任务由于没有任何强指针而被释放,然后调用cancel,我还重写authorize以返回由创建的任务buildPOSTTask并将其分配给我的测试中的变量。任务仍然被取消。

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

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

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

编辑:

我决定在这里发布整个项目。无论如何,这东西完成后将是开源的,而我获得的 API 凭据是用于测试应用程序的。

ALCKit

4

4 回答 4

15

在为此苦苦挣扎了 6 天,并在谷歌上不停地寻找解决方案之后,我真的很高兴地说我终于弄明白了。

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

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

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
}
于 2016-07-21T19:30:16.680 回答
0

你的服务器坏了。。

tcp_connection_cancel 1
nw_socket_handle_socket_event Event mask: 0x4
nw_socket_handle_socket_event Socket received WRITE_CLOSE event
nw_endpoint_handler_cancel [1 anilist.co:443 ready resolver (satisfied)]
nw_endpoint_handler_cancel [1.1 104.28.1.44:443 ready socket-flow (satisfied)]
__nw_socket_service_writes_block_invoke sendmsg(fd 9, 31 bytes): socket has been closed
nw_endpoint_flow_protocol_error [1.1
104.28.1.44:443 cancelled socket-flow (null)] Socket protocol sent error: [32] Broken pipe
nw_endpoint_flow_protocol_disconnected [1.1 104.28.1.44:443 cancelled socket-flow (null)] Output protocol disconnected
nw_endpoint_handler_cancel [1.2 104.28.0.44:443 initial path (null)] 
nw_resolver_cancel_on_queue 0x60800010da40
[NWConcrete_tcp_connection dealloc] 1
[User Defaults] CFPrefsPlistSource<0x6180000f8700> (Domain: XIO.PrivateAPITest, User: kCFPreferencesCurrentUser, ByHost: No, Container: (null)) is waiting for writes to complete so it can determine if new data is available

它无限等待“写入”完成..

它发送请求..进行 SSL 握手并且没有得到响应。它超时并认为这是一个损坏的请求..

class WTF : NSObject, URLSessionDelegate {

    var urlSession: URLSession!

    override init() {
        super.init()

        urlSession = URLSession(configuration: .default, delegate: self, delegateQueue: nil)

        var request = URLRequest(url: URL(string: "https://anilist.co/api/auth/access_token?client_secret=REMOVED&grant_type=authorization_code&redirect_uri=genericwebsitethatshouldntexist.bo&client_id=ibanez-hod6w&code=REMOVED")!)
        request.httpMethod = "POST"

        let data = try! JSONSerialization.data(withJSONObject: ["Test":"Test"], options: [])

        urlSession.uploadTask(with: request, from: data).resume()
    }

    func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

        completionHandler(.performDefaultHandling, nil)

    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didSendBodyData bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) {

    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: NSError?) {

    }

    func urlSession(_ session: URLSession, task: URLSessionTask, willPerformHTTPRedirection response: HTTPURLResponse, newRequest request: URLRequest, completionHandler: (URLRequest?) -> Void) {

        completionHandler(request)

    }

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: (URLSession.ResponseDisposition) -> Void) {

        completionHandler(.allow)

    }

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {

    }
}
于 2016-07-16T03:03:18.497 回答
0

您是否有机会使用 Ensighten 等第三方库?我在 XCode 8 beta 中遇到了完全相同的问题(在 XCode 7 中运行良好),并且我所有带有 nil 参数的块都导致崩溃。原来是图书馆做了一些编码导致了这个问题。

于 2016-07-28T16:07:58.540 回答
0

对我来说,这是一个导致问题的弱参考,所以我改变了

completion: { [weak self] (response: Result<ResponseType, Error>)

completion: { [self] (response: Result<ResponseType, Error>)
于 2022-02-03T23:39:35.007 回答