'pass data from web server and show it on viewcontroller

I have data from a server which I need to show on another View Controller. Note I had perform a POST request. Note I have 2 ViewControllers

these are the fields:

firstName

lastName

emailAddress

mobileNumber

This is the code that started the web service POST (data downloaded)

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let profileVC = segue.destination as? ProfileViewController else {return}
    profileVC.nameLabel.text = self.firstName
    profileVC.idNumberLabel.text = self.idNumber
    profileVC.emailAddressLabel.text = self.emailAddress
    profileVC.mobileNumberLabel.text = self.mobileNumber

This is where the downloaded data is supposed to show

private func updateUI(firstName: String, lastName: String, emailAddress: String, mobileNumber: String) {
    self.nameLabel.text = firstName + "" + lastName
    self.idNumberLabel.text = idNumber
    self.emailAddressLabel.text = emailAddress
       
}

this is the post request code

// Prepare URL
let url = URL(string: stringURL)
guard let requestUrl = url else { fatalError() }

// Prepare URL Request Object
var request = URLRequest(url: requestUrl)
request.httpMethod = "POST"

// Set HTTP Request header
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("1088", forHTTPHeaderField: "Content-Length")

// HTTP Parameters which will be sent in HTTP Request body
let postString = "userID=\(useridTextField.text)&password=\(passwordTextField.text)";

// Set HTTP Request Body
request.httpBody = postString.data(using: String.Encoding.utf8)

// Perform HTTP Request
let session = URLSession.shared
let task = session.dataTask(with: request) { data, response, error in
    
    guard let data = data else {
        return
    }
    
    do {
        var response = try JSONDecoder().decode(User.self, from: data)
        response.idNumber = self.idNumber
        response.firstName = self.firstName
        response.middleName = self.middleName
        response.lastName = self.lastName
        response.emailAddress = self.emailAddress
        response.mobileNumber = self.mobileNumber
        response.landline = self.landline
        
        
        return
    } catch {
        let str = String(decoding: data, as: UTF8.self)
        print(str)
        
    }
    
}
task.resume()


Solution 1:[1]

Here is an example using Publish/Observer pattern with Notifications

I start with this simple extension that helps me organize notification names

extension Notification.Name {

    static let DidLoginSuccessfully
        = Notification.Name("DidLoginSuccessfully")
}

Let's say you have a Network class with a launch request function that launches your network request.

Once you have successfully got a response and decoded your response to a URL object, you can publish / post a notification to any observers

fileprivate func launchRequest() {
    
    // Prepare URL
    let url = URL(string: stringURL)
    guard let requestUrl = url else { fatalError() }

    // Prepare URL Request Object
    var request = URLRequest(url: requestUrl)
    request.httpMethod = "POST"

    // Set HTTP Request header
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
    request.setValue("1088", forHTTPHeaderField: "Content-Length")

    // HTTP Parameters which will be sent in HTTP Request body
    let postString = "userID=\(useridTextField.text)&password=\(passwordTextField.text)";

    // Set HTTP Request Body
    request.httpBody = postString.data(using: String.Encoding.utf8)

    // Perform HTTP Request
    let session = URLSession.shared
    let task = session.dataTask(with: request) { data, response, error in
        
        guard let data = data else {
            return
        }
        
        do {
            // Change response variable name to user
            var user = try JSONDecoder().decode(User.self, from: data)
            user.idNumber = self.idNumber
            user.firstName = self.firstName
            user.middleName = self.middleName
            user.lastName = self.lastName
            user.emailAddress = self.emailAddress
            user.mobileNumber = self.mobileNumber
            user.landline = self.landline
            
            // Publish the notification
            NotificationCenter.default.post(name: .DidLoginSuccessfully,
                                            object: user)
            
            
        } catch {
            let str = String(decoding: data, as: UTF8.self)
            print(str)
            
        }
    }
    
    task.resume()
}

Then in the module where you need some data to be updated, you need to observe / listen this notification

For example, let's say this was a view controller, you need to observe this notification and when you get notified of this event, you need to manage this.

class SomeCustomVC: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        subscribeToNotifications()
    }
    
    deinit {
        unsubscribeFromNotifications()
    }
    
    
    private func subscribeToNotifications() {
        
        // Sets the view controller to list to this notification
        NotificationCenter.default.addObserver(self,
                                               selector: #selector(didLoginSuccessfully(_:)),
                                               name: .DidLoginSuccessfully,
                                               object: nil)
    }
    
    // Your button login event handler
    private func didTapLoginButton() {
        // Make the segue or API request as you do
    }
    
    private func unsubscribeFromNotifications() {
        NotificationCenter.default.removeObserver(self,
                                                  name: .DidLoginSuccessfully,
                                                  object: nil)
    }
    
    // Your update UI function
    private func updateUI(firstName: String,
                          lastName: String,
                          emailAddress: String,
                          mobileNumber: String) {
        self.nameLabel.text = firstName + "" + lastName
        self.idNumberLabel.text = idNumber
        self.emailAddressLabel.text = emailAddress
    }
}

// Notification Observer
extension SomeCustomVC {
    
    @objc func didLoginSuccessfully(_ notification: Notification) {
        
        if let user = notification.object as? User {
            
            updateUI(firstName: user.firstName,
                     lastName: user.lastName,
                     emailAddress: user.emailAddress,
                     mobileNumber: user.mobileNumber)
            
        }
    }
}

Give this a go and see if it helps you.

If you are looking for something more sophisticated like binding, you can have a look at this Combine tutorial.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shawn Frank