2017-04-25 20 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,您可以在將來輕鬆維護或更新您的代碼,這將更容易理解。 –