I have a beginner question about protocols and functions in Swift. I’ve been following along with Angela Yu’s course for about a month.
I’m trying to wrap my head around how in the code below, the function "textFieldShouldReturn" can be activated without being called.
import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var conditionImageView: UIImageView!
@IBOutlet weak var temperatureLabel: UILabel!
@IBOutlet weak var cityLabel: UILabel!
@IBOutlet weak var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
searchTextField.delegate = self
}
@IBAction func searchPressed(_ sender: UIButton) {
print (searchTextField.text!)
searchTextField.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
print (searchTextField.text!)
searchTextField.endEditing(true)
return true
}
I understand that because the WeatherViewController is connected to the protocol UITextFieldDelegate, I am able to access functions such as func textFieldShouldReturn or func textFieldShouldEndEditing. But I’m struggling to visualise what’s happening behind the scenes, that makes it possible for the functions to activate when I run the program even though my code does not explicitly calls it.
If someone can explain like I’m 5, that would be greatly appreciated.
3
Answers
This is the wrong sentence here. The correct one is:
Imagine this (although it’s just a concept):
UIButton
as thereturn
button of the keyboard.touchUpInside
event of that button calls this:delegate
is notnil
and thetextFieldShouldReturn
is implemented in your code, your code will be called. Otherwise, a default implementation will be executed instead.Note that it is just a concept and it is not the real implementation of the
UITextField
classUITextFieldDelegate is a protocol. When you have inherited your controller with this Protocol it means now all the functions(calls of this Protocol, in our case TEXTFIELD) can be received in the controller.
In viewDidLoad, you have told your specific textfield(in our case it is "searchTextField") to give you all the calls of textfield in this controller.
The tl;dr answer is that, when your view loads, your
WeatherViewController
sets itself as the delegate ofsearchTextField
and it issearchTextField
that is calling your function.You are probably aware that everything you see in the user interface of your app is implemented as a Swift object[*]. In the case of
searchTextField
the object is an instance ofUITextField
. This object is responsible for everything to do with the search text field on the screen. It draws the text field and its contents and it manages all the input. So, if you press a key when the field has focus, it is theUITextField
that accepts the input, updates the content and tells the windowing system that it needs to be redrawn. In the case of the return key being pressed, theUITextField
will have some default action, which, I think is to surrender focus and let the windowing system move to the next field.The delegate is an object that
UITextField
uses to allow you to modify the default behaviour at various points. A delegate implements a collection of functions that are called at various points in the life cycle of theUITextField
. So, recognising that you might not want the default behaviour when the return key is pressed, theUITextField
textFieldShouldReturn
UITextField
calls it.You can do pretty much anything you like in the delegated function, within certain limits and then the
UITextField
checks the return value to see if it should also do the default action.I have a couple of notes on terminology:
WeatherViewController
is not connected to the protocol. We say it adopts the protocol or it conforms to the protocol. The protocol sets constraints for classes and structs that adopt it. Usually the methods listed in a protocol must be implemented in the class that adopts it. This is not the case withUITextFieldDelegate
– the methods are all marked as optional – but it does place the constraint that your class must be an Objective-C class. Optional methods don’t exist for pure Swift classes. In your case,UIViewController
is an Objective-C class and you inherit from it, so the constraint is satisfied.Sorry to be a bit picky about the language, but I find it really helps to get things straight in my head if I adopt the correct terminology.
[*] Objective-C object actually