0

I want to check when the user starts editing a text field. There is a great clear answer on how to do that here.

However, in my case my textField is within a UITableview that's set up as its own class. I've tried lots of different ways to get this to work, but I keep getting the crash "libc++abi.dylib: terminating with uncaught exception of type NSException" I put a break in the textFieldDidChange func and it never gets called so the problem seems to be with how I'm calling that func from the target.

class TextFieldCell: UITableViewCell { lazy var textField: UITextField = { let tf = UITextField() tf.translatesAutoresizingMaskIntoConstraints = false tf.textAlignment = .center tf.textColor = .black tf.font = UIFont.systemFont(ofSize: 17) tf.clearButtonMode = .whileEditing return tf }() // For simplicity, the rest of the Cell setup not shown. // Adds target in AirInput VC to fire method when editing happens textField.addTarget(self, action: #selector(AirInputViewController.textFieldDidChange(_:)), for: UIControl.Event.editingChanged) } class AirInputViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate { @objc func textFieldDidChange(_ textField: UITextField) { } } 

I also tried the following for the target and it crashes as well.

textField.addTarget(AirInputViewController.self, action: #selector(AirInputViewController.textFieldDidChange(_:)), for: UIControl.Event.editingChanged) 

It feels like I'm missing something simple, but I have no idea what that simple fix is. Or perhaps should I add the target in the AirInputViewContoller? If so, how would I access the UITableViewCells where the Text Field is? Thanks!

3
  • Usually there is a pointer to what caused the exception before "terminating with uncaught exception of type NSException.". Would you mind posting the whole crash? Commented Mar 10, 2019 at 19:10
  • Do you mean this? "libc++abi.dylib: terminating with uncaught exception of type NSException" Commented Mar 10, 2019 at 19:19
  • No, usually the output is waaaay longer. I have a hunch of what can be happening. Posted an answer. If it's not the case, I can just delete it. Commented Mar 10, 2019 at 19:21

1 Answer 1

1

Probably your crash is due to the fact that you do:

textField.addTarget(self, action: #selector(AirInputViewController.textFieldDidChange(_:)), for: UIControl.Event.editingChanged) 

Here self is TextFieldCell, so I think it tries to go and check that AirInputViewController is inside TextFieldCell, which is not the case.

I would do:

class TextFieldCell: UITableViewCell { weak var delegate: TextFieldCellDelegate? lazy var textField: UITextField = { // same you have }() textField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: UIControl.Event.editingChanged) @objc func textFieldDidChange(_ textField: UITextField) { delegate?.textFieldDidChange(textField) } 

Create a fancy delegate:

protocol TextFieldCellDelegate: class { func textFieldDidChange(_ textField: UITextField) } class AirInputViewController: TextFieldCellDelegate { func textFieldDidChange(_ textField: UITextField) { // textField just changed! } // IMPORTANT! Set the delegate for the cell! func tableView(...cellForRow...) { let cell = ... as! TextFieldCell cell.delegate = self ... return cell } } 

Hope that helps.

Sign up to request clarification or add additional context in comments.

6 Comments

I think I see where you are going, but can't quite get it to work. What is the purpose of the protocol? I get the error "objc can only be used with members of classes, @objc protocols, and concrete extensions of classes" when implementing it.
I am sorry, the protocol and its textFieldDidChange should have not been @objc. The purpose of the protocol is to create a delegate. The events inside the cell are then handled within the cell and one uses the delegate to inform the controller about the events the controller needs to know about, nothing else. Basically the event observer for a view should be inside that view, not in a different class.
I appreciate the help. Now without the @objc it gives the error "Protocol methods must not have bodies".
That did the trick! Thanks so much for working through that with me and teaching me something new. Now I just need to stare at it for a while to internalize what's going on better. :)
The Delegate Pattern is very useful and spread in Swift, so I advise you to get familiar with it. Here some examples and explanations for it: stackoverflow.com/questions/7168714/…. The protocol here inherits from class so the variable can be weak and that way avoid a retention cycle because the controller has the view and the view would have a reference of the controller as the delegate. So by making the delegate weak, the view does not have a strong reference to the controller and there is no cycle.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.