How to pass data between controller, checker and back using callback closures Swift

Viewed 162

I'm a newbie in Swift and this is my very first question I want to ask the community. I have a viewcontroller with a textField, custom button and a label and also I have a separate checker to check whether the entered in textField word is correct or not. So when I push the button the checker is checking and changing the color of the label (green/ red / transparent if textfield.text is empty. How can I implement this using callback closure? Thank you so much in advance!

Here is my ViewController:

final class FeedViewController: UIViewController {

    private let checkTextField: UITextField = {
        let textField = MyCustomTextField(
            font: UIFont.systemFont(ofSize: 16),
            textColor: .black,
            backgroundColor: .white,
            placeholder: "Enter the word")
        
        return textField
    }()
    
    private lazy var checkButton: UIButton = {
        let button = MyCustomButton(
            title: "Check the word",
            titleColor: .white,
            backgroundColor: .systemGray,
            backgroundImage: nil) {

        }
        button.layer.cornerRadius = 6
        button.clipsToBounds = true
        return button
    }()
    
    private let colorLabel: UILabel = {
        let label = UILabel()
        label.alpha = 0
        label.toAutoLayout()
        return label
    }()
 
    private let checker: CheckTextField
    
    init(checker: CheckTextField) {
        self.checker = checker
        super .init(nibName: nil, bundle: nil)
    }

Here is my Checker:

class CheckTextField {
    
    private let correctWord = "correct word"
    
    func check( word: String) {
        

    }
}

I have managed to complete this task with notifications, but closures for me are too much complicated :(

2 Answers

you can define your clousure in data sending class as follow

class DataSenderClass  {
var dataPassClousure:((String)->Void)?
func sendHere(){
    // i am invoking closure from here
    dataPassClousure?("hi i am data")
}

} here is dataPassClousure accepting string as argument(you can adjust according to your choice or can use object as well or can also pass multiple arguments to your closure) to be sent/passed to receiver class. Just listen to fresh data in your data receiver class as follow

class DataReceiverClass {
let senderObject = DataSenderClass()
func receiveHere() {
    //each time data change from sendHere function this closure invoke . perform your action
    senderObject.dataPassClousure = {arug1 in
        print("received data is \(arug1)")
    }
}

}

The closure is actually a parameter of the method that receives and calls it, so if you want check(word:) to call some closure when it finishes checking, you'll need to add that as a parameter:

func check(word: String, closure: ()->Void)

If you want to pass a parameter to the closure, you'll need to specify that too:

func check(word: String, closure: (status: CheckResult)->Void)

I just made up CheckResult here; I just needed some type that you can use to convey the result of the check. It could be a an enumeration, for example:

enum CheckResult {
    case ok;
    case bad;
    case empty;
}

Now, inside your check function, you can call the closure with the appropriate value, like: closure(.ok). To be more concrete, let's fill in your empty function:

class CheckTextField {
    private let correctWord = "apple"
    
    func check(word: String, closure: (_ status: CheckResult)->Void) {
        if word.count == 0 {
            closure(.empty)
        } else if word == correctWord {
            closure(.ok)
        } else {
            closure(.bad)
        }
    }
}

Then we can use it this way:

let checker = CheckTextField()

checker.check(word:"apple") { print($0) }       // ok
checker.check(word:"pear") { print($0) }        // bad
checker.check(word:"jackfruit") { print($0) }   // bad
checker.check(word:"") { print($0) }            // empty

You can replace the print($0) with code to set the label color or whatever else you might want to do. That's nice, because it keeps details about your view out of the CheckTextField class.

Related