变量未正确保存
Posted
技术标签:
【中文标题】变量未正确保存【英文标题】:Variable is not saved correctly 【发布时间】:2021-03-15 05:28:35 【问题描述】:在函数中,我将数据从 json 字符串解析到字典,然后将其保存到变量中。但是当我尝试从另一个函数调用变量时,数据没有保存。
代码是:
var usersData: [String: NSArray] = [:]
@IBAction func buttonTapped(_ sender: UIButton)
if let url = URL(string: "https://medaljson.aadev151.repl.co/get-data")
URLSession.shared.dataTask(with: url) data, response, error in
if let data = data
if let jsonString = String(data: data, encoding: .utf8)
let data: Data? = jsonString.data(using: .utf8)
let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [String:NSArray]
self.usersData = json!
.resume()
if shouldPerformSegue(withIdentifier: "loginSegue", sender: nil)
performSegue(withIdentifier: "loginSegue", sender: nil)
override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool
if identifier == "loginSegue"
print(self.usersData) // [:]
let name = nameTF.text ?? ""
let surname = surnameTF.text ?? ""
let ssa = ssaTF.text ?? ""
if usersData[ssa] == nil
errorLabel.text = "SSA not found"
return false
else if usersData[ssa]![0] as! String != name || usersData[ssa]![0] as! String != surname
errorLabel.text = "Name / Surname doesn't match"
return false
else
return true
return true
我想知道如何解决问题。 感谢您的帮助:)
【问题讨论】:
虽然与您的具体问题无关,这已经在下面得到了回答,但值得指出的是,如果 JSON 解码失败,像这样 (self.usersData = json!
) 的强制展开 json
将使您的程序崩溃。您可能需要查看if let
或do/try/catch
以避免这种潜在的崩溃。
也不相关:永远不要自己调用包含will
、did
或should
的方法。它们仅由框架调用。并且根本不要在 Swift 中使用 NS...
集合类型。
@jnpdx 我知道,这段代码只是一个测试。但无论如何,谢谢:)
【参考方案1】:
URLSession.shared.dataTask(with
调用完成块/闭包异步,因为您更新闭包内的self.usersData = json!
,self.userData
也会异步更新,当您调用if shouldPerformSegue(withIdentifier: "loginSegue", sender: nil)
作为立即下一条语句时URLSession.shared.dataTask(with
(同步) 所以运行时执行 if 语句和 performSegue(withIdentifier:
甚至在执行闭包之前因此当 shouldPerformSegue(withIdentifier
被执行时你的数据不会更新
if let url = URL(string: "https://medaljson.aadev151.repl.co/get-data")
URLSession.shared.dataTask(with: url) data, response, error in
if let data = data
if let jsonString = String(data: data, encoding: .utf8)
let data: Data? = jsonString.data(using: .utf8)
let json = (try? JSONSerialization.jsonObject(with: data!, options: [])) as? [String:NSArray]
self.usersData = json! //as mentioned by jnpdx in comment above, this statement is error prone. Because its out of scope of the question I havent updated it, if you need to know how to assign the value safely, lemme know
DispatchQueue.main.async
if self.shouldPerformSegue(withIdentifier: "loginSegue", sender: nil)
self.performSegue(withIdentifier: "loginSegue", sender: nil)
.resume()
编辑:随着 cmets 中不相关但重要的点越来越多,我相信我在回答中也解决所有这些问题对我来说是唯一正确的,尽管它们与问题本身并不严格相关.上面的答案应该为 OP 的问题提供正确的解释,但同时也需要解决其他问题。
if let url = URL(string: "https://medaljson.aadev151.repl.co/get-data")
URLSession.shared.dataTask(with: url) data, response, error in
if let data = data, let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
self.usersData = json
DispatchQueue.main.async
if self.shouldPerformLoginSegue()
self.performSegue(withIdentifier: "loginSegue", sender: nil)
.resume()
func shouldPerformLoginSegue() -> Bool
let name = nameTF.text ?? ""
let surname = surnameTF.text ?? ""
let ssa = ssaTF.text ?? ""
if usersData[ssa] == nil
errorLabel.text = "SSA not found"
return false
else if usersData[ssa]![0] as! String != name || usersData[ssa]![0] as! String != surname
errorLabel.text = "Name / Surname doesn't match"
return false
else
return true
几件事,
您已经在使用try?
,因此您无需包装
do
catch
中的声明,但我真的希望你知道
它的后果,如果 JSONSerialisation
出于任何原因结束
向上抛出错误,try?
将返回值nil
,并且
因为你将let json = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
代码放入 if let 条件永远不会被执行。
这是一种处理方式,另一种是捕获错误并处理
如果您决定使用,则适当地(根据您的用例)
该方法改用try
。 try!
的另一个变种
你可以阅读并决定哪一个对你来说更有意义。
正如 Vadian 提到的,实际上没有必要使用任何 NS
集合类型,而是可以使用它们的 swift 对应物,在
在这种情况下Array
,数组采用通用参数Element
和
因为在这种情况下它不能隐式推断Element
的类型,
它要求您明确指定,因为我不完全确定
json 结构我建议你可以使用Array<Any>
但你的
shouldPerformSegue(withIdentifier
中的代码让我失望,我
不要认为你的代码可以处理数组,看起来你是
期待一本字典,因为我也无法推断出类型
选择[String: Any]
随意设置
再次如 Vadian 所述,您永远不应该手动调用 shouldPerformSegue(withIdentifier:
,您可以覆盖它
并且显然可以返回一个布尔值,指示是否
是否应该执行特定的segue,但你不应该调用
手动。
shouldPerformSegue(withIdentifier:
仅在以下情况下被调用
storyboard segues 并且在你调用时不会被调用
performSegue(withIdentifier:
手动/显式。阅读link了解更多信息。
我了解您只想在确定时执行转场
条件都满足了,但是很明显当你打电话的时候
performSegue(withIdentifier:
ios 假设你已经
执行了各种检查,并且您想明确执行
segue 因此它不会调用shouldPerformSegue(withIdentifier:
再次检查。
因此,您需要在显式调用之前处理这些检查
performSegue(withIdentifier:
本身因此我添加了一个新的
实例方法shouldPerformLoginSegue() -> Bool
告诉你
您是否应该执行特定的 loginSegue
在您的代码中 if let jsonString = String(data: data, encoding: .utf8) let data: Data? = jsonString.data(using: .utf8)
是
完全没有必要,将数据转换为 JSON 毫无意义
字符串并再次将其重新转换为Data
并将此数据传递给
JSONSerialization
你已经有来自数据任务的数据
响应,只需将其传递给JSONSerialization
。
我当前对shouldPerformLoginSegue
的实现有很多副作用,如果您打算遵循pure functional programming
和concern separation
的原则,绝对不是正确的方法,但这里的想法只是为了展示您如何将您的代码 shouldPerformSegue
移动到您自己的另一个实例函数中,并在调用 performSegue
之前将其用作检查
【讨论】:
@vadian:感谢您的 cmets,我更新了我的答案,并添加了更多关于 OP 应该做什么以及原因的解释:) 太棒了!非常感谢!你能告诉我为什么来自 TF 和 JSON 数据的完全相同的字符串可能不相等吗? 感谢您的回答,我不确定您的问题是什么,请您详细说明一下吗? “请告诉我为什么来自 TF 和 JSON 数据的完全相同的字符串可能不相等?” TF 中的字符串是什么意思,抱歉,我不确定 TF 的首字母缩写词:| 是的,当然,我会澄清的。我的意思是当我调用 shouldPerformLoginSegue() 并打印数据时,它说surname
(文本字段的值)和usersData[ssa]![0]
(字典的值)并不相等,而实际上它们是相等的。我知道这听起来可能仍然令人困惑,所以如果确实如此,请告诉我:)
谢谢你的帮助和所有的解释,我真的很感激 :) 但实际上我发现我并不真的需要第二个文本字段,所以我会离开程序只有一个,可以正常工作:)以上是关于变量未正确保存的主要内容,如果未能解决你的问题,请参考以下文章