swift - 当主线程等待运行时,Alamofire 从不调用 encodingCompletion 来使用 MultipartFormData 进行上传

标签 swift asynchronous concurrency alamofire

我有这种形式的代码:

func myFunction(<...>, completionHandler: (ResponseType) -> Void) {
    <prepare parameters>

    mySessionManager.upload(multipartFormData: someClosure,
        to: saveUrl, method: .post, headers: headers) { encodingResult in
          // encodingCompletion
          switch encodingResult {
                case .failure(let err):
                    completionHandler(.error(err))
                case .success(let request, _, _):
                    request.response(queue: self.asyncQueue) { response in
                        // upload completion
                        <extract result>
                        completionHandler(.success(result))
                    }
            }
     }
}

并测试这样的代码:

func testMyFunction() {
    <prepare parameters>

    var error: Error? = nil
    var result: MyResultType? = nil

    let sem = DispatchSemaphore(value: 0)
    var ran = false
    myFunction(<...>) { response in
        if ran { 
            error = "ran twice"
            return
        }
        defer {
            ran = true
            sem.signal()
        }

        switch response {
            case .error(let err): error = err
            case .success(let res): result = res
        }
    }
    sem.wait()

    XCTAssertNil(error, "Did not want to see this error: \(error!)")

    <test response>
}

我使用信号量来阻塞主线程,直到异步处理请求;这对于我所有其他 Alamofire 请求都适用,但不适用于这个。测试挂起。
(注意:使用 active waiting 不会改变任何事情。)

使用调试器,我发现

现在我最好的猜测是 DispatchQueue.main.async 说,“当有时间时在主线程上执行这个”——它永远不会,因为我的测试代码在那里阻塞(无论如何,都会进行进一步的测试)。

我将其替换为 self.queue.async 和 upload.delegate.queue.addOperation,这是同一函数中的另外两个排队操作。然后测试运行通过但产生意外错误;我的猜测是,encodingCompletion 被调用太早

这里有几个问题要问;任何问题的答案都可以解决我的问题。

  1. 我可以以不同的方式测试此类代码,以便 DispatchQueue.main 可以执行其他任务吗?
  2. 如何使用调试器找出哪个线程在何时运行?
  3. 我该如何适应 Alamofire at the critical position这样就不需要主队列了?

最佳答案

如上所述here ,这是一个糟糕的“解决方案”,因为它在嵌套请求时引入了死锁的可能性。我将其留在这里用于教学目的。

<小时/>

改变

DispatchQueue.main.async {
    let encodingResult = MultipartFormDataEncodingResult.success(
            request: upload,
            streamingFromDisk: true,
            streamFileURL: fileURL
        )

    encodingCompletion?(encodingResult)
}

SessionManager.swift

self.queue.sync {
    ...
}

解决(阅读:解决)问题。

我不知道这是否是一个可靠的修复或其他什么;我有filed an issue .

关于swift - 当主线程等待运行时,Alamofire 从不调用 encodingCompletion 来使用 MultipartFormData 进行上传,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42644111/

相关文章:

swift - 继承父工厂方法

ios - 具有顺序和限制的 Firestore 复合查询

java - Spring 集成 - 需要后端异步处理的 Web 服务网关的即时响应

c# - 捕获可能从 Subscription OnNext Action 抛出的异常

java - 迭代器中的 .next 引发的并发修改异常

ios - 在应用程序委托(delegate)中设置初始 View Controller 时如何设置 UITabBarController

swift - 在 MVVM 模式中使用 RxSwift 处理用户注册和登录

javascript - 使用回调的意义和原因?

Java Lock支持内存一致性

去旅游#5 : select statement example