当主线程等待其运行时,Alamofire永远不会通过MultipartFormData调用encodingCompletion进行上传 [英] Alamofire never calls encodingCompletion for upload with MultipartFormData when main thread is waiting for it to run

查看:273
本文介绍了当主线程等待其运行时,Alamofire永远不会通过MultipartFormData调用encodingCompletion进行上传的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这种形式的代码:

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要求都很有效-但不是这个要求。测试挂起。

(请注意,使用主动等待不会改变。)

I use a semaphore to block the main thread until the request is processed asynchronously; this works fine for all my other Alamofire requests -- but not this one. The test hangs.
(Note bene: Using active waiting does not change things.)

使用调试器,我发现

  • all code that executes does so just fine but
  • encodingCompletion is never called.

现在,我最好的猜测是 DispatchQueue.main.async 说:在有时间的时候在主线程上执行此操作 –它永远不会,因为我的测试代码在那儿阻塞了(无论如何都会运行进一步的测试)。

Now my best guess is that DispatchQueue.main.async says, "execute this on the main thread when it has time" -- which it never will, since my test code is blocking there (and will run further tests, anyway).

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

I replaced it with self.queue.async and upload.delegate.queue.addOperation, two other queueing operations found in the same function. Then the test runs through but yields unexpected errors; my guess is that then, encodingCompletion is called too early.

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

There are several questions to ask here; an answer to any can solve my problem.


  1. 我可以以不同的方式测试此类代码,以使 DispatchQueue.main 可以执行其他任务吗?

  2. 如何使用调试器找出哪个线程在何时运行?

  3. 如何使用适应 Alamofire在关键位置不需要主队列?

  1. Can I test such code differently so that DispatchQueue.main can get to other tasks?
  2. How can I use the debugger to find out which thread runs when?
  3. How can I adapt Alamofire at the critical position so that it does not require the main queue?


推荐答案

我们不应该阻塞主线程。 XCTest有自己的等待异步计算的解决方案:

We should not block the main thread. XCTest has its own solution for waiting on asynchronous computations:

let expectation = self.expectation(description: "Operation should finish.")
operation(...) { response in
    ...
    expectation.fulfill()
}
waitForExpectations(timeout: self.timeout)

来自文档


在处理事件的同时运行运行循环,直到满足所有期望或超时。客户端在使用此API时不应操纵运行循环。

Runs the run loop while handling events until all expectations are fulfilled or the timeout is reached. Clients should not manipulate the run loop while using this API.






在XCTest之外,我们可以使用与 XCTestCase.waitForExpectations()可以:

var done = false
operation(...) { response in
    ...
    done = true
}

repeat {
    RunLoop.current.run(until: Date(timeIntervalSinceNow: 0.1))
} while !done

注意:假设操作将其工作发送到同一队列上。如果它使用另一个队列,将无法使用;但是使用 DispatchSemaphore 的方法(请参阅问题)不会导致死锁并可以使用。

Note: This assumes that operation sends its work to the same queue itself is executed on. If it uses another queue, this won't work; but then the approach using DispatchSemaphore (see the question) does not cause a deadlock and can be used.

XCTest中的实现做得更多(期望值高,超时,可配置的睡眠间隔等),但这是基本机制

The implementation in XCTest does a lot more (multiple expectations, timeout, configurable sleep interval, etc.) but this is the basic mechanism.

这篇关于当主线程等待其运行时,Alamofire永远不会通过MultipartFormData调用encodingCompletion进行上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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