Reputation: 61
I have a class that has two member variables and a function. The function is called when the user navigates to a new storyboard and uses a http GET request with member variable y to assign a value to member variable x. After the function is finished, I try to assign x to the new storyboard's variable, however it is nil. How do I assign a value to x within the function and then pass x to the new storyboard?
import UIKit
import os.log
class testViewController: UIViewController {
var x: XClass!
var y = “1234”
override func viewDidLoad() {
super.viewDidLoad()
}
// MARK: - Navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
super.prepare(for: segue, sender: sender)
switch(segue.identifier ?? "") {
case “ZViewController”:
guard let zviewcontroller = segue.destination as? ZViewController else{
fatalError("Unexpected Destination: \(segue.destination)")
}
loadXDetail()
zviewcontroller.x = x
default:
os_log("Not ZViewController Segue", log: OSLog.default, type: .debug)
}
}
private func loadX(){
// credentials encoded in base64
let username = “***”
let password = “***”
let loginData = String(format: "%@:%@", username, password).data(using: String.Encoding.utf8)!
let base64LoginData = loginData.base64EncodedString()
// create the request
let url = URL(string: "https://example.com")!
var request = URLRequest(url: url)
request.httpMethod = "GET"
request.setValue("Basic \(base64LoginData)", forHTTPHeaderField: "Authorization")
//making the request
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print("\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse {
// check status code returned by the http server
print("status code = \(httpStatus.statusCode)")
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let items = json["items"] as? [[String: Any]] ?? []
for dic in items{
//guard let api = dic["Type"] as? String else {return}
let a = dic[“A”] as! String
let b = dic[“B”] as! String
let c = dic[“C”] as! String
self.x = XClass(y: y, a: a, b: b, c: c)!
}
} catch let error as NSError {
print(error)
return
}
}
}
task.resume()
}
}
Upvotes: 0
Views: 87
Reputation: 4159
swift 4.2 / Xcode 10.1:
There are few ways to pass data between viewControllers or classes.
The easiest one is using Global variable. For Example:
import UIKit
var myGlobalVariable = "" //Or any Type you need
class testViewController: UIViewController {
private func loadX(){
//Do some stuff ...
myGlobalVariable = x
}
import UIKit
class ZViewController: UIViewController {
override func viewDidLoad() {
print(myGlobalVariable)
}
Or, using singleton pattern. For Example:
Create a class like:
import Foundation
class SetVariable {
var test: String? //Or any type you need
private init () {}
static let shared = SetVariable.init()
}
class testViewController: UIViewController {
private func loadX(){
//Do some stuff ...
SetVariable.shared.test = x
}
class ZViewController: UIViewController {
override func viewDidLoad() {
print(SetVariable.shared.test)
}
Upvotes: 1
Reputation: 100503
You can't prevent a segue inside prepare(for segue
until your request finishes , you need to start the call to the asynchonous method when you need to navigate
loadX()
then inside the completion of let task = URLSession.shared.dataTask(with: request)
do
self.x = XClass(y: y, a: a, b: b, c: c)!
}
DispatchQueue.main.async {
self.performSegue(withIdentifier:"SegueID",sender:nil)
}
and at that moment the x var has a correct value according to the response
another thing you may need x as any array as it will contain the last value from this loop
for dic in items{
//guard let api = dic["Type"] as? String else {return}
let a = dic[“A”] as! String
let b = dic[“B”] as! String
let c = dic[“C”] as! String
self.x = XClass(y: y, a: a, b: b, c: c)!
}
plus consider using Codable
to decode your response instead of JSONSerialization
Upvotes: 1