swift - 仅在收到数据时才快速启动视图
问题描述
我正在使用以下函数从 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()
}
}
解决方案
您不能阻止视图控制器“启动”本身(除非根本不推送/呈现/显示它)。一旦你推送/呈现/展示它,它的生命周期就不能——也不应该——停止。因此,您有责任为“加载状态”加载适当的 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?
}
推荐阅读
- css - 如何根据需要设计 ::before 语音气泡 V 形?
- c# - Httpclient 缓慢的内存增加问题 - 使用多线程的任务 Whenall
- azure-data-explorer - Azure 数据资源管理器 - 在用户定义函数的扩展运算符中使用标量输入作为列名参数
- python - 安装自己的项目作为依赖 | 模块名称问题
- python - 在python中导入CV2给出未定义的符号错误
- flutter - 在 Flutter 中跟踪 setState 调用
- azure-active-directory - 首次使用访客用户作为全局管理员登录 azsphere
- tsql - SQL SERVER V 2017 only 函数如何在兼容级别较低的数据库上运行
- swagger - Web API 2 和 Swagger
- tcl - tcl close 不会优雅地终止 tcp/ip 连接