swiftuikit

How to exchange data between view controllers?


I have PurchaseViewController with purchase buttons. I need to show the controller with a simple parents check (ParentsVerificationController) if the user taps one of the buttons in PurchaseViewController. If verification in ParentsVerificationController was completed successfully, I need to return to PurchaseViewController and finish the purchase. I use this code:

PurchaseViewController:

verificationState == false

@objc func weeklyButtonAction() {
        let detailController = SLVerification()
        detailController.modalPresentationStyle = .overFullScreen
        self.present(detailController, animated: false, completion: nil)
        
        if verificationState == true {
            print("good")
        }
    }
    
    @objc func monthlyButtonAction() {
        let detailController = SLVerification()
        detailController.modalPresentationStyle = .overFullScreen
        self.present(detailController, animated: false, completion: nil)
        
        if verificationState == true {
            print("good")
        }
    }
    
    @objc func annualButtonAction() {
        let detailController = SLVerification()
        detailController.modalPresentationStyle = .overFullScreen
        self.present(detailController, animated: false, completion: nil)
        
        if verificationState == true {
            print("good")
        }
    }

ParentsVerificationController:

@objc func buttonAction(sender: SLButton!) {
        switch (sender.tag) {
        case 0: if buttonsArray[0] == a {
            print("success")
            let presenter = PurchaseController()
            presenter.verificationState = true
            dismissVerification()
        } else {
            print("failure")
            shakeAnimation()
            dismissVerification()
        }
        case 1: if buttonsArray[1] == a {
            print("success")
            let presenter = PurchaseController()
            presenter.verificationState = true
            dismissVerification()
        } else {
            print("failure")
            shakeAnimation()
            dismissVerification()
        }
        case 2: if buttonsArray[2] == a {
            print("success")
            let presenter = PurchaseController()
            presenter.verificationState = true
            dismissVerification()
        } else {
            print("failure")
            shakeAnimation()
            dismissVerification()
        }
        case 3: if buttonsArray[3] == a {
            print("success")
            let presenter = PurchaseController()
            presenter.verificationState = true
            dismissVerification()
        } else {
            print("failure")
            shakeAnimation()
            dismissVerification()
        }
        default: print("error")
        }
    }

I return to PurchaseViewController with "success" but if else statement in weeklyButtonAction, monthlyButtonAction and annualButtonAction doesn't call. I can't see "good". How to fix it?


Solution

  • Everytime buttonAction called, you are creating a new PurchaseController therefore, you are not notifing changes to the old PurchaseViewController. To fix your problem, I recommend using delegate pattern:

    class ParentsVerificationController {
        weak var delegate: ParentsVerificationControllerDelegate?
        @objc func buttonAction(sender: SLButton!) {
            switch (sender.tag) {
            case 0:
                if buttonsArray[0] == a {
                    delegate?.didVerificationSuccess()
                    dismissVerification()
                } else {
                    shakeAnimation()
                    dismissVerification()
                }
                ...
            }
        }
    }
    
    
    class PurchaseViewController {
        @objc func weeklyButtonAction() {
            let detailController = ParentsVerificationController()
            detailController.delegate = self
            detailController.modalPresentationStyle = .overFullScreen
            self.present(detailController, animated: false, completion: nil)
        }
    }
    
    extension PurchaseViewController: ParentsVerificationControllerDelegate {
        func didVerificationSuccess() {
            print("good")
        }
        
    }
    

    An alternative for delegate in Swift is using closure:

    class ParentsVerificationController {
        var didVerificationSuccess: (() -> Void)?
        @objc func buttonAction(sender: SLButton!) {
            switch (sender.tag) {
            case 0:
                if buttonsArray[0] == a {
                    didVerificationSuccess?()
                    dismissVerification()
                } else {
                    shakeAnimation()
                    dismissVerification()
                }
                ...
            }
        }
    }
    
    
    class PurchaseViewController {
        @objc func weeklyButtonAction() {
            let detailController = ParentsVerificationController()
            detailController.didVerificationSuccess = {
                print("good")
            }
            detailController.modalPresentationStyle = .overFullScreen
            self.present(detailController, animated: false, completion: nil)
        }
    }