我正在尝试使用我的数据库验证用户的登录信息。当按下登录按钮时,我想根据从数据库返回的信息来说明是否会发生segue。我首先将变量决策设置为true,如果我无法验证用户,我想将其设置为false并阻止segue。这是我的代码,但它有一个问题。最后的return语句总是如此。基本上发生的是在从数据库返回响应之前首先调用.resume()之后的return语句。有人可以澄清为什么会这样吗
override func shouldPerformSegue(withIdentifier identifier: String,sender:
Any?) -> Bool
{
var decision = true
let url = URL(string:"http://192.23.25.98/login/php")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
let body = "UserNameLogIn=\(userName.text!.lowercased())&PasswordLogIn=\(passWord.text!.lowercased())"
request.httpBody=body.data(using: String.Encoding.utf8)
URLSession.shared.dataTask(with: request) { (data:Data?, response:URLResponse?, error:Error?) in
if (error == nil)
{
DispatchQueue.main.async(execute: {
do
{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? Dictionary<AnyHashable,AnyObject>
guard let parseJson = json else{
print ("error parsing")
return
}
let status = parseJson["status"]
if (status != nil)
{
if (parseJson.count>3)
{
decision = true
}
else
{
decision = false
}
}
}
catch
{
print("error: \(error)")
}
})
}
else
{
decision = false
}
}.resume()
return decision
}
答案 0 :(得分:1)
而不是在点击按钮时启动segue并尝试捕获shouldPerformSegue(withIdentifier:sender:)
内的异步进程,而是应该让按钮定义执行验证请求的@IBAction
并以编程方式启动如果它成功了。
因此:
从按钮中删除segue。
通过 control 在视图控制器之间添加segue - 从第一个场景上方的条形图中的视图控制器图标拖拽到第二个场景:
选择segue并在属性检查器中为其命名:
从按钮中移除了segue后,您现在可以将按钮连接到@IBAction
方法:
完成验证逻辑后,您的登录操作应为performSegue(withIdentifier:sender:)
:
performSegue(withIdentifier: "NextSceneSegue", sender: self)
E.g。
@IBAction func didTapLoginButton(_ sender: Any) {
let url = URL(string:"http://192.23.25.98/login/php")
var request = URLRequest(url: url!)
request.httpMethod = "POST"
request.httpBody = ["UserNameLogIn": useridTextField.text!, "PasswordLogIn": passwordTextField.text!]
.map { $0.key + "=" + $0.value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)! }
.joined(separator: "&")
.data(using: .utf8)
URLSession.shared.dataTask(with: request) { data, response, error in
DispatchQueue.main.async {
guard let data = data, let httpResponse = response as? HTTPURLResponse, (200 ..< 300) ~= httpResponse.statusCode, error == nil else {
// handle basic network errors here
return
}
guard let json = (try? JSONSerialization.jsonObject(with: data)) as? [String: Any] else {
// handle json parsing errors here
return
}
if json["status"] == nil {
// handle missing status here
return
}
guard json.count > 3 else {
// handle incorrect count here
return
}
self.performSegue(withIdentifier: "NextSceneSegue", sender: self)
}
}.resume()
}
注意,我百分比编码请求正文中的值。特别是密码可能包含保留字符。我没有犯错误使用.urlQueryAllowed
,而是使用了.urlQueryValueAllowed
,其中我提取了一些保留字符:
extension CharacterSet {
/// Returns the character set for characters allowed in the individual parameters within a query URL component.
///
/// The query component of a URL is the component immediately following a question mark (?).
/// For example, in the URL `http://www.example.com/index.php?key1=value1#jumpLink`, the query
/// component is `key1=value1`. The individual parameters of that query would be the key `key1`
/// and its associated value `value1`.
///
/// According to RFC 3986, the set of unreserved characters includes
///
/// `ALPHA / DIGIT / "-" / "." / "_" / "~"`
///
/// In section 3.4 of the RFC, it further recommends adding `/` and `?` to the list of unescaped characters
/// for the sake of compatibility with some erroneous implementations, so this routine also allows those
/// to pass unescaped.
static var urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed = CharacterSet.urlQueryAllowed
allowed.remove(charactersIn: generalDelimitersToEncode + subDelimitersToEncode)
return allowed
}()
}