首页 > 解决方案 > 仅在收到数据时才快速启动视图

问题描述

我正在使用以下函数从 API 获取信息,在该函数中我传入一个单词的字符串。有时,如果 API 中不可用该词,我会生成一个新词并尝试该词。问题是因为这是一个异步函数,当我启动出现来自 API 的值的页面时,它有时为空,因为该函数仍在后台运行,试图生成 API 中存在的单词。如何确保仅在从 api 收到数据时才启动页面?

static func wordDefin (word : String, completion: @escaping (_ def: String )->(String)) {
        let wordEncoded = word.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
        let uri = URL(string:"https://dictapi.lexicala.com/search?source=global&language=he&morph=false&text=" + wordEncoded! )
        if let unwrappedURL = uri {
            var request = URLRequest(url: unwrappedURL);request.addValue("Basic bmV0YXlhbWluOk5ldGF5YW1pbjg5Kg==", forHTTPHeaderField: "Authorization")
            let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
                do {
                if let data = data {
                    let decoder = JSONDecoder()
                    let empty = try decoder.decode(Empty.self, from: data)
                    if (empty.results?.isEmpty)!{
                        print("oops looks like the word :" + word)
                        game.wordsList.removeAll(where: { ($0) == game.word })
                        game.floffWords.removeAll(where: { ($0) == game.word })
                        helper.newGame()
                    } else {
                        let definition =  empty.results?[0].senses?[0].definition
                        _ = completion(definition ?? "test")
                        return
                    }
                    }
                }
                catch {
                    print("connection")
                    print(error)
                }
        }
            dataTask.resume()
        }
    }

标签: swiftxcode

解决方案


您不能阻止视图控制器“启动”本身(除非根本不推送/呈现/显示它)。一旦你推送/呈现/展示它,它的生命周期就不能——也不应该——停止。因此,您有责任为“加载状态”加载适当的 UI,它可能是带有加载微调器的空白视图控制器。您可以随心所欲地执行此操作,包括.isHidden = true为所有视图对象加载完整的 UI。这个想法是在数据库在后台工作时尽可能多地预加载 UI,这样当数据准备好时,您可以用尽可能少的工作来显示完整的 UI。

我建议您在“加载”配置中加载 UI 后,下载数据作为流程中的最后一步,并使用完成处理程序完成任务:

override func viewDidLoad() {
    super.viewDidLoad()

    loadData { (result) in
        // load full UI
    }

}

您的数据方法可能如下所示:

private func loadData(completion: @escaping (_ result: Result) -> Void) {
    ...
}

编辑

考虑创建一个按照以下方式运行的数据管理器。因为数据管理器是一个类(引用类型),所以当你将它传递给其他视图控制器时,它们都指向管理器的同一个实例。因此,任何视图控制器对其所做的更改都会被其他视图控制器看到。这意味着当您推送一个新的视图控制器并且需要更新标签时,请从data属性中访问它。如果它还没有准备好,等待数据管理器在它准备好时通知视图控制器。

class GameDataManager {

    // stores game properties
    // updates game properties
    // does all thing game data

    var score = 0
    var word: String?

}

class MainViewController: UIViewController {

    let data = GameDataManager()

    override func viewDidLoad() {
        super.viewDidLoad()

        // when you push to another view controller, point it to the data manager
        let someVC = SomeOtherViewController()
        someVC.data = data

    }

}

class SomeOtherViewController: UIViewController {

    var data: GameDataManager?

    override func viewDidLoad() {
        super.viewDidLoad()

        if let word = data?.word {
            print(word)
        }

    }

}

class AnyViewController: UIViewController {

    var data: GameDataManager?

}

推荐阅读