2017-04-25 19 views
0

我有一个登录页面来收集用户名和密码。在提交时,它将发送到数据库以检索我们的服务器访问密钥。我通过使用session.dataTask的异步JSON POST来完成此操作。当我检索JSON对象时,我将它解析出来。我想将它传递到下一页,检索Firebase令牌,然后将这两部分数据发送回服务器进行数据库存储。我创建了一个“准备继续”函数,收集变量并将其传递给下一页的变量。我相信我没有正确设置事件序列,或者数据没有超出Async容器。有人可以看看这两个文件,看看我错了吗?Swift 3.0 iOS10通过用于Firebase的segue发件人传递异步数据

这里是第一页我想从制作REST Web服务调用后Segue公司了......

loginVC.swift:

import UIKit 

class LoginVC: UIViewController { 

    @IBOutlet weak var username: UITextField! 
    @IBOutlet weak var password: UITextField! 
    @IBOutlet weak var validationBox: UITextView! 
    @IBAction func logInAction(_ sender: UIButton) { 
     guard let user = username.text, !user.isEmpty else { 
      validationBox.text = "Please enter valid credentials" 
      return 
     } 
     guard let pass = password.text, !pass.isEmpty else { 
      validationBox.text = "Please enter valid credentials" 
      return 
     } 

     let params = ["sUser": username.text!, "sPass": password.text!] 

     let url = URL(string: "restWebServiceURL")! 
     let session = URLSession.shared 
     var request = URLRequest(url: url) 
     request.httpMethod = "POST" 
     do { 
      request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) 
     } catch let error { 
      print(error.localizedDescription) 
     } 
     request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
     request.addValue("application/json", forHTTPHeaderField: "Accept") 

     let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in 

      guard error == nil else { return } 
      guard let data = data else { return } 

      do { 
       if let parsedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { 
        let parsedData = parsedJSON["d"] as! [String:Any] 
        let key = parsedData["key"] as! String 
        DispatchQueue.main.async { 
         print(key) 
         self.performSegue(withIdentifier: "FirebaseVC", sender: key) 
        } 

       } 
      } catch let error { 
       print(error.localizedDescription) 
      } 
     }) 
     task.resume() 
    } 
    func sayHello() { 
     print("Hello!") 
    } 
    func sayGoodbye() { 
     print("Goodbye!") 
    } 



    override func viewDidLoad() { 
     super.viewDidLoad() 
     validationBox.text = "Ready..." 
     func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
      if let FirebaseInit = segue.destination as? FirebaseVC { 
       if let sKey = sender as? String { 
        print("prepare - " + sKey) 
        FirebaseInit.sessionKey = sKey 
       } 
      } 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 


} 

这里是我想去的页面接收到的数据访问密钥...

FirebaseVC.swift:

import UIKit 

class FirebaseVC: UIViewController { 

    private var _sessionKey = String() 

    var sessionKey : String { 
     get { return _sessionKey } 
     set { _sessionKey = newValue } 
    } 

    @IBOutlet weak var sessionKeyTestBox: UITextView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     print(_sessionKey) 

    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 



} 

随意建议将数据传递到下一页的更好方法。谢谢...

+0

PS:我们在提交时并没有说快速,这没有错,但它不存在,无论如何,我想邀请您考虑使用像singleton这样的设计模式:逻辑非常简单使用从服务器获得的数据实例化一个类,并且在需要时调用此对象,并且由于一个用户可以一次连接(singleton将保证该类只有一个实例) –

+0

我不喜欢使用单身人士,只是我个人的意见....我会改变'如果让FirebaseInit = segue.destination为? FirebaseVC {'to'if(segue.destination.isKind(of:FirebaseVC.self)){let vc = segue.destination as! FireBaseVC'但这些都差不多......你可以在prepareForSegue中设置一个断点,并确保你的sKey被正确地转换为字符串? –

+0

好吧,我使用该模型构建了Android应用程序和Web应用程序应用程序,所以我完全不反对它。你能提供一些指导吗? –

回答

1

事实证明,在我的假设中,我认为事件链是关闭的。继@achrefGassoumi提出的模型,我搬到了datatask一个集服务在这里:

import Foundation 

struct CallWebService { 

    static let sharedInstance = CallWebService() 

    func logInToCaduceus(u: String, p: String, completion: @escaping (_ sKey: String) ->()) { 
     let params = ["sUser": u, "sPass": p] 

     let url = URL(string: "https://telemed.caduceususa.com/ws/telemed.asmx/telemedLogin")! 
     let session = URLSession.shared 
     var request = URLRequest(url: url) 
     request.httpMethod = "POST" 
     do { 
      request.httpBody = try JSONSerialization.data(withJSONObject: params, options: .prettyPrinted) 
     } catch let error { 
      print(error.localizedDescription) 
     } 
     request.addValue("application/json", forHTTPHeaderField: "Content-Type") 
     request.addValue("application/json", forHTTPHeaderField: "Accept") 

     let task = session.dataTask(with: request as URLRequest, completionHandler: { data, response, error in 

      guard error == nil else { return } 
      guard let data = data else { return } 

      do { 
       if let parsedJSON = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { 
        let parsedData = parsedJSON["d"] as! [String:Any] 
        let key = parsedData["key"] as! String 
        DispatchQueue.main.async { 
         completion(key) 
        } 
       } 
      } catch let error { 
       print(error.localizedDescription) 
      } 
     }) 
     task.resume() 

    } 

} 

然后我的两个控制器是这样的:

LoginVC

import UIKit 

class LoginVC: UIViewController { 

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
     if (segue.destination.isKind(of: FirebaseVC.self)) { 
      let vc = segue.destination as! FirebaseVC 
      if let sKey = sender as? String { 
       vc.sessionKey = sKey 
      } 
     } 
    } 

    @IBOutlet weak var username: UITextField! 
    @IBOutlet weak var password: UITextField! 
    @IBOutlet weak var validationBox: UITextView! 
    @IBAction func logInAction(_ sender: UIButton) { 
     guard let user = username.text, !user.isEmpty else { 
      validationBox.text = "Please enter valid credentials" 
      return 
     } 
     guard let pass = password.text, !pass.isEmpty else { 
      validationBox.text = "Please enter valid credentials" 
      return 
     } 

     CallWebService.sharedInstance.logInToCaduceus(u: username.text!, p: password.text!, completion: {(sessionKey: String) -> Void in 
       print(sessionKey) 
       self.performSegue(withIdentifier: "FirebaseVC", sender: sessionKey) 
      } 
     ) 

    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     //validationBox.textAlignment = .center 
     validationBox.text = "Ready..." 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 


} 

和接收FirebaseVC

import UIKit 

class FirebaseVC: UIViewController { 

    private var _sessionKey = String() 

    var sessionKey : String { 
     get { return _sessionKey } 
     set { _sessionKey = newValue } 
    } 

    @IBOutlet weak var sessionKeyTestBox: UITextView! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     sessionKeyTestBox.text = _sessionKey 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
    } 

} 

对不起我的(非快速)Javascript术语,但es基本上我将数据调用移动到服务中,然后使用完成方法在服务中放置回调方法,以确保performSegue在数据收到并解析出来之前不会触发。因此,当我将表单数据中的日志提交给服务器时,在异步调用完成之前,segue不会触发。

+0

伟大的工作,很高兴听到:),我有以下注释: - 您可以添加一个模型层,就像您使用您希望在其他VC中访问的数据实例化的类一样,也许是 - “确保performSegue在接收到数据之前不会触发“并不是一个真正的问题,因为如果像我告诉过你的那样添加一个模型图层,那么当您从类创建的对象不是零时,登录就会成功,您可以继续使用应用程序。 - Singleton是swift非常需要的设计模式之一,所以我想邀请你继续阅读它。 –

+0

您可以将appDelegate的数据添加到该模型中吗? –

+0

就我所知你不能:它只需从appDelegate中获取视图控制器中的变量,然后用你想要的数据在View控制器中初始化你的模型类(在它上面创建一个对象)。 如果您正确实现了MVC,您可以在将来轻松维护或更新您的代码,这将更容易理解。 –