【问题标题】:Completion Handler executed before Request is complete在请求完成之前执行的完成处理程序
【发布时间】:2019-11-16 17:09:26
【问题描述】:

我有一个使用UIImagePickerController 选择图像的应用。然后将该图像传递给 API 函数。一旦该功能完成,我将使用委托将结果传递给带有结果的模态显示控制器。但是,模态控制器出现在完成块之前,并且我的错误 AlerViewController 警报永远不会被调用。

API 在后台线程中运行,我已在主线程上设置完成(因为它更新 UI - 呈现模态控制器)但它在完成完全执行之前被调用。

代码如下;

API 请求

func searchImage(with image: UIImage, to viewController: UIViewController, success: @escaping([ViImageResult]?) -> Void) {
        var results = [ViImageResult]()
        let params = ViUploadSearchParams(image: image)
        ViSearch.sharedInstance.uploadSearch(params: params, successHandler: { (data : ViResponseData?) -> Void in
            guard let data = data else { return }
            if data.result.isEmpty {
                AlertViewController.noResultsFound(viewController: viewController)
                return
            } else {
                if data.hasError {
                    AlertViewController.dataError(viewController: viewController)
                    return
                } else {
                    for response in data.result {
                        results.append(response)
                    }
                    DispatchQueue.main.async {
                        success(results)
                    }
                }
            }
        }, failureHandler: {
            (error) -> Void in
            AlertViewController.dataError(viewController: viewController)
        })
    }

控制器

var selectedImage: UIImage? {
        didSet {
            guard let selectedImage = selectedImage else { return }
            ViSearchSDKService.shared.searchImage(with: selectedImage, to: self) { (results) in
                guard let results = results else { return }
                if self.resultsDelegate != nil {
                    self.resultsDelegate?.recievedResults(recievedResults: results)
                }
            }
            let resultsController = ResultsViewController()
            self.resultsDelegate = resultsController
            let navigationController = UINavigationController(rootViewController: resultsController)
            navigationController.modalPresentationStyle = .overFullScreen
            DispatchQueue.main.async {
                self.present(navigationController, animated: true, completion: nil)
            }
        }
    }

在 API 请求中,我所有的 AlertViewController 函数都在主线程上调用,然后从请求中返回。成功块也在主线程上调用。

我在这里做错了什么?...

更新

我不太清楚为什么会这样,但它可以满足我的一切需求。我已将 API 请求移到了

之外的另一个函数中
var selectedImage: UIImage? {
        didSet {

在我的控制器中。

新的工作代码

var selectedImage: UIImage? {
        didSet {
            guard let selectedImage = selectedImage else { return }
            self.searchImage(with: selectedImage)
        }
    }

    func searchImage(with image: UIImage) {
        ViSearchSDKService.shared.searchImage(with: image, to: self) { (results) in
            guard let results = results else { return }
            let resultsController = ResultsViewController()
            self.resultsDelegate = resultsController
            if self.resultsDelegate != nil {
                self.resultsDelegate?.recievedResults(recievedResults: results)
            }
            let navigationController = UINavigationController(rootViewController: resultsController)
            navigationController.modalPresentationStyle = .fullScreen
            DispatchQueue.main.async {
                self.present(navigationController, animated: true, completion: nil)
            }
        }
    }

【问题讨论】:

  • 我并没有真正关注您的问题,但那些 guard let results = results else { return }guard let data = data else { return } 行是在没有任何调试/错误处理的情况下可能发生的路径。也许在里面放一个debugPrint,看看它是否走那条路¯_(ツ)_/¯
  • 我的控制器代表在任务完全完成之前被调用。我想我需要为 for 循环添加一个调度组。
  • data.result 中的响应
  • 你有没有设置一个断点,看看它是否到达了代码的那部分?
  • 你甚至不需要 for 循环... results.append(contentsOf: data.results) developer.apple.com/documentation/swift/array/3126941-append ,绝对不需要任何访问控制或等待它。

标签: swift grand-central-dispatch dispatch completionhandler


【解决方案1】:

我想你想要这个。

    var selectedImage: UIImage? {
        didSet {
            // make sure it was not set to nil
            guard let selectedImage = selectedImage else { return }

            // set up your view controller for the response
            let resultsController = ResultsViewController()
            self.resultsDelegate = resultsController
            let navigationController = UINavigationController(rootViewController: resultsController)

            // do your search
            ViSearchSDKService.shared.searchImage(with: selectedImage, to: self) { (results) in
                // leave no path without visible side-effect
                guard let results = results else { debugPrint("nil results"); return }

                // now that we have the result, present your results view controller
                navigationController.modalPresentationStyle = .overFullScreen
                DispatchQueue.main.async {
                    self.present(navigationController, animated: true) { in

                        // once done presenting, let it know about the results
                        self.resultsDelegate?.recievedResults(recievedResults: results)
                    }
                }
            }
        }
    }

【讨论】:

  • 这也有效。我认为委托的设置是在错误的地方。
猜你喜欢
  • 1970-01-01
  • 2021-10-31
  • 2016-09-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多