I am working with keyboard resign features in iPhone app development. I would like to know why
self.textField.delegate = self
needs to be included into the viewDidLoad of a viewController. I have tried to find reasons of this but no explanation has been clear so far.
A few points
The reason you need to set the delegate is because without it the view doesn't know about the view controller. So it wouldn't know about your method textFieldDidEndEditing and it would never be called.
That is the basic premise of delegate, you are telling that object, "here is an object that I want you to call methods on"
It doesn't have to be set in viewDidLoad - but it's often the most convient place to set up delegates for views.
The delegate doesn't have to be the view controller (self), in your case it's the simplest way, but with a UITableView its common to have another class be the delegate so that all the logic isn't in one place and so it can be changed.
The UITextFieldDelegate protocol defines methods that you use to manage the editing and validation of text in a UITextField object. All of the methods of this protocol are optional.
A text field calls the methods of its delegate in response to important changes. You use these methods to validate text that was typed by the user, to respond to specific interactions with the keyboard, and to control the overall editing process. Editing begins shortly before the text field becomes the first responder and displays the keyboard (or its assigned input view).
From more info. check apple doc.
Its not necessary to use self.textField.delegate = self if you don't want to manage the editing and validation of text in a UITextField object as all the methods of UITextFieldDelegate is optional.
For your other questions like what does .delegate = self do??
When you "set the delegate," what you are doing is saying where you want the messages to go.
Hence,
blah.delegate = amazingPlace will send the messages to "amazingPlace".
blah.delegate = somewhereElse will send the messages to "somewhereElse".
blah.delegate = self will send the messages to you.
... check this source link for details
Delegates are key concepts in iOS development so I'd suggest taking a good look at the documentation for them. It can be particularly useful to create your own custom delegates in certain situations too so understanding and using them in the right places can really help improve the structure of your projects.
There are a couple of key reasons for using them. Firstly, they allow safe communication between classes. In your example, the textField object that you're using is communicating back to your view controller. This is why you need to set your view controller as its delegate. Otherwise the text field doesn't have a delegate object (your view controller) to communicate with. The text field fires certain methods at certain times, such as textFieldDidBeginEditing, and calls these on its delegate object if it has one. When you register your view controller as the text view's delegate you can tap into these callbacks.
The other benefit is that delegates allow you to separate concerns and encapsulate or abstract responsibilities. It might be that the main concern for the text view is how to handle text in its view but not necessarily what to do when has been entered, or when the return button in the keyboard is pressed, or how to validate text that has been input. It's better that these tasks are handed over to something else, such as a delegate (in Obj-C parlance), and that is why in your example you have to register one class as the delegate for another.
As stated before, UITextfield delegation allows you to control events on your textfield.
You ll have the ability to edit functions like
textFieldShoulEndEditing
or
textFieldDidEndEditing
in order to add custom rules, for example : text validation.
Take a look at Apple doc.
If you don't need it, you can delete this line and UITextfieldDelegate on your class declaration.
You need to either set the delegate of a UITextField in code with self.textField.delegate = self
or make your viewcontroller (or any other class) a delegate with class MyViewController: UITextFieldDelegate and set the delegate of the UITextField in the storyboard by control dragging from the textfield to the viewController.
Related
Is there any delegate getting fired when the user taps the OTP suggestion that iOS provides?
I know that I could use UITextFieldDelegate methods to detect changes in the textfield's text property, but knowing that the user has pressed the button would make things so much easier...
According to Apple's article: About the Password AutoFill Workflow
For iOS apps, the system always sends a textDidChangeNotification notification when a view has been modified. It also calls one of the delegate methods of the view—but the exact method depends on the view’s type:
UITextField: The system calls your UITextFieldDelegate object’s textField(_:shouldChangeCharactersIn:replacementString:) method.
UITextView: The system calls your UITextViewDelegate object’s textView(_:shouldChangeTextIn:replacementText:) method.
Custom View adopting the UITextInput protocol: The system calls the insertText(:) method or replace(:withText:) in the UIKeyInput protocol.
You can create a subclass of UITextField or UITextView and override insertText(:) method and replace(:withText:) method, it will be called when user tap quickbar.
In my case, I found that when I got a text in Should change Charater I got two empty spaces, there I come to know that it is autofill characters, so according to it, I update my four text field one by one.
I am using JJMaterialTextField custom UITextField class. It has some delegates for animation placeholder etc..I want to use some other delegates too for UIViewController which uses that class. If I write down delegate.self for JJMaterialTextField class object in UIViewController, I does not perform its own delegates, it perform only delegates methods in UIViewController. But I want to that it should perform both delegate methods. How can I do it? Thanks.
Done use delegates in the view control, instead use this
[textField addTarget:self
action:#selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
It will behave like delegate it will fire when text changes, there are also other selectors textFieldDidBegin.. etc.
This way you wont interrupt the delegates.
It is mostly considered a bad idea if you need multiple delegates. Delegates are all about 1-1 relationship.
Please read the answer here, it will give you pointers on how you could proceed with observers or with notifications
Multiple Delegates in iOS
If you don't want to go with the recommendations above take a look at first and second answer on how you can do it, basically create a object that holds references to multiple delegates, then you can just look over them and post delegate methods that way:
Delegation to multiple objects
I have tried to make a location autocomplete text view class by subclassing UITextField and use Google Place Autocomplete API. This works great, but I have a design error due to the implementation. To observe when the user types text, I set the UITextFieldDelegate to self in the custom subclass and track changes to the typed text in textView:shouldChangeTextInRange:replacementText:. This works, but here is the design error: If someone now wants to check what is typed into the custom subclass by setting the delegate to something new, the delegate of my class is not set to the object of the class itself anymore. Now the custom class is useless. Is there any way to either get the text as it is typed without the delegate, prevent the delegate from being changed, or in any other way fix my problem?
A few options I have though about that could work, but in a bad way:
Check regularly what the text property is: Should be obvious why busy waiting is a stupid idea
Override the delegate property and set it to private: Not sure if this will even work, but if it did, the class is no longer a proper subclass of UITextField and all delegate methods are unavailable when implementing my subclass.
Provide a new delegate for further use of the delegate: Allows someone to get the same things as the UITextFieldDelegate provides, but it still messes up the documentation and proper implementation of UITextField
Delegates in UIKit I normally one to one connections. Which can cause the problem you have described.
If you want multiple delegates of a UITextField I would derive a class from UITextField for example MYTextField and add a method to addDelegate and removeDelegate that maintains a list of delegates. The sent the MYTextField's delegate to itself and broadcast any delegate method to all listeners in the delegate array.
this post shows example code on how do maintain a list of multiple delegates.
Delegation to multiple objects
Say I write a UITextField subclass and want to have control over the text written into it by the user. I would set the input field's delegate to be myself and implement -textField:shouldChangeCharactersInRange:replacementString:.
However, I would still want to allow whatever part of code uses me as a text field to implement the usual delegate methods. An approach for that would be to store a second delegate reference and map them like so:
- (id)init {
self = [super init];
super.delegate = self;
return self;
}
- (void)setDelegate:(id)delegate {
self.nextDelegate = delegate;
}
- (id)delegate {
return self.nextDelegate;
}
I would then proceed to implement all UITextFieldDelegate methods and forward them to the next delegate as I wish. Obviously, I may want to modify some parameters before passing them on to the next delegate, like in -textField:shouldChangeCharactersInRange:replacementString:.
Another problem I'm thinking of is when the user's sets nextDelegate to the text field itself (for whatever reason), resulting in an infinite loop.
Is there a more elegant way to hijack delegate callbacks like in the example code I posted?
The problem with your approach is the overridden delegate accessor: There's no guarantee that Apple's code always uses the delegate ivar directly and does not use the getter to access the delegate. In that case it would just call through to the nextDelegate, bypassing your sneaked in self delegate.
You might have checked that your approach works in the current implementation but this could also change in future UIKit versions.
Is there a more elegant way to hijack delegate callbacks like in the example code I posted?
No, I'm not aware of any elegant solutions. You could not override the delegate accessor and instead set up secondary delegate (to which you have to manually pass all delegate messages).
To solve the actual problem of filtering text input it might be worthwhile looking into
- (void)replaceRange:(UITextRange *)range withText:(NSString *)text;
This method is implemented by UITextField (as it adopts UITextInput) and could be overridden to filter the text argument.
I think you're thinking about this correctly, and the approach you outlined will work fine (I've done it).
There's no circularity issue because you shouldn't expose nextDelegate in the subclass's public interface, so no caller will have the chance to setup a cycle. (You could also test in the setter that delegate != self.
It would be better, though, if you could avoid this altogether. For example, if you just want to tweak the text field text as it changes, you can get the control event:
[self addTarget:self action:#selector(didChange:) forControlEvents:UIControlEventEditingChanged];
Then,
- (void)textFieldDidChange:(id)sender {
self.text = [self alteredText];
}
- (NSString *)alteredText {
// do whatever transform to user input you wish, like change user input 'a' to 'x'
return [self.text stringByReplacingOccurrencesOfString:#"a" withString:#"x"];
}
This will work as well, but with the odd side effect that the delegate won't see the alteredText in shouldChangeCharactersInRange:. That's fixable by making alteredText public and having the class customers call it instead of the standard getter.
All of the problems with subclassing can be avoided by using a different approach of intercepting delegate messages: A "delegate proxy".
The idea is to use an intermediate object (derived from NSProxy) that either responds to a delegate message or passes it along to the next delegate. It's basically what you did by subclassing the UITextField but instead of using the text field object we'll use a custom object that handles only the interception of some delegate messages.
These customized delegate proxys form a set of reusable building blocks which are simply plugged into each other to customize the behavior of any object that uses delegation.
Here's an example (code on github) of a chain of delegates:
UITextField -> TextFilterDelegate -> SomeViewController
The UITextField passes delegate messages to TextFilterDelegate which responds to textField:shouldChangeCharactersInRange:replacementString: and passes other delegate messages on to its own delegate (the view controller).
I've got a view controller xib file with several views in it. I'm building a wizard-type interface. I'm just doing a simple fade between the views, and I'm already using a navigation controller for the main interface. I'd prefer not to use one for this wizard. Anyway, in the views, each panel has at least a button, some sort of input field (usually a UITextField) and some helper text hard coded in a UILabel.
The problem is that not all the UITextField objects are calling the textFieldDidChange method in the delegate (File's Owner - .m file associated with the xib), but all the UITextField objects ARE calling the textFieldDidBeginEditing method.
Makes no sense to me. I feel like I must be missing something simple in how I set up the screens, but I'll be darned if I can figure it out. Each of the screens all look identical in the property sheets (on the right hand side of Xcode), and everything is wired up correctly in the File's Owner property sheet, both in IBOutlet and IBActions.
Here are some shots of what's going on...
Ideas? Thanks.
Here are links to the screen caps of the vital parts.
(being a new member is making it hard to add all the info I need with screen caps!)
As far as I now, there is no delegate method with the header textFieldDidChange. You have created a method of your own, which is depending on a NSNotification. Make sure all the UITextFields are send the right notification.
There is no such method on a UITextFieldDelegate
You may have confused textViewDidChange, which is a delegate method for a UITextView, but itis passed the UITextView that generated the event, not an NSNotification.
Seems like you want textField:shouldChangeCharactersInRange:replacementString: instead.
This is resolved. I'm a knucklehead. :-)
I was attaching my own notifier/observer and hadn't done so for the last few UITextField objects. Sorry to bother y'all.