3

I've created a subclass of UITextField which has its own visual style and functionality. The functionality is to restrict the user to decimal currency values (for example, 3.50), but that's not really relevant because I know the algorithm I have works. The issue is that I want to contain that logic in the text field subclass itself. So far I've succeeded in capturing the delegate equivalents of textFieldDidBeginEditing and textFieldDidEndEditing:

NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBeginEditing", name: UITextFieldTextDidBeginEditingNotification, object: self)
NSNotificationCenter.defaultCenter().addObserver(self, selector: "didEndEditing", name: UITextFieldTextDidEndEditingNotification, object: self)

Working well. Now I need a way to check if the user is entering valid input and update its text only if that character is valid (like shouldChangeCharactersInRange, but without a delegate), but I need to do this from within that text field subclass itself. Otherwise, I'm just repasting 40 lines of code in every view controller that has this type of field.

Ryan Bobrowski
  • 2,641
  • 3
  • 31
  • 52

1 Answers1

4

So far I've succeeded in capturing the delegate equivalents of textFieldDidBeginEditing and textFieldDidEndEditing

But you've gone about this wrong way. Don't use notifications; there is no need.

Simply have the UITextField subclass make self the delegate of self!

self.delegate = self

Now all the UITextFieldDelegate methods will arrive to the UITextField subclass itself. Implement any of those methods that interest you, right there in the subclass, and you're done.

That approach, however, has one drawback: you've "stolen" the text field's delegate and cannot easily make some other object the delegate. So here's another approach: set up the UITextField subclass as the target of its own Editing Changed event. This has the advantage that it doesn't prevent other objects from being the target, because a UIControl event can be sent to multiple targets.

(Of course, I suppose you could use the UITextFieldTextDidChangeNotification instead.)

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • hmm yeh that's what I did at first, but then I was reading some stackoverflow questions on the topic and some people were saying it's not neat, could lead to problems, and at the very least is not the intended use of delegation. Of course I can't find those answers right now, but it's totally okay to set a class' delegate as itself? – Ryan Bobrowski May 25 '15 at 16:17
  • Absolutely. Cocoa doesn't care who the delegate is. Try it! – matt May 25 '15 at 16:17
  • 2
    The problem is that whenever I do need to use the view controller as the delegate, I have to overwrite the existing delegate of self, which removes all of the unique functionality of the field unless I recode it in the view controller. Is there any way around this? – Ryan Bobrowski May 26 '15 at 06:30
  • 1
    Modified my answer to include some more possibilities. Or you could get into _message forwarding_ if the worst comes to the worst... – matt May 26 '15 at 15:08
  • @matt, how do you implement approach #2: set an object as a target of the EditingChanged event, in code, in Swift? Searched all over and haven't found an example of how to do that. I tend to get confused anytime I have to use selectors in Swift. – stone Jun 17 '15 at 23:37
  • 1
    @skypecakes Here's an example from my book: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch13p620dialogsOniPhone/ch26p888dialogsOniPhone/ViewController.swift – matt Jun 18 '15 at 00:01
  • @matt Thank you thank you! For anyone reading this later, here's the magic line of code: `tf.addTarget(self, action: "textChanged:", forControlEvents: .EditingChanged)` – stone Jun 18 '15 at 03:00