Still I couldn't understand completely how these delegate methods are getting called.
I have UIViewController,UITextFieldDelegate in one class which will call its delegate methods without specifying like textField.delegate = self;
But for some different purposes like UIWebViewDelegate we are supposed to enter like webView.delegate = self; and it seems like it is calling its delegate methods. Perfect.
But now I am facing a problem. I am using CLLocationManagerDelegate and also CALayer in same class. For both I am giving location.delegate =self; and layer.delegate =self; At some point both are conflicting each other and only one of the thing is working either CLLocationManagerDelegate or CALayer. The other thing is getting stopped. I don't why it so happens like this? Any reason? How can we overcome this. Even I planned to use some other frameWork, say UIWebView . I will face same problem for those delegate methods also. Can you tell me why it is working in that way ?
The classes that will call its delegates without you specifying them have default implementations, which means that they already know what to do, and will only change their behavior if you override these methods.
Setting 2 or more classes to the same delegate should not interfere with each other (unless for a very weird reason in where the method is named the same in both custom classes).
Your problem is most likely the fact that you havent implemented those methods or are using those classes wrong.
For example, Location manager requires you to create an instance, configure it and START running updates. The most common method for a delegate of this type is the "did update location" (or something like that). Which you have to implement if you want to be informed of every time a new location is received. Otherwise you have to read the location manually whenever you desire.
As a suggestion, every time you set a delegate for an object, you have to do the object.delegate = self; thing. And you probably noticed that you will get a warning until you specify in the header that it conforms to that protocol: for example.
Just control click the UITextFieldDelegate word.
Look for the methods under #required, THOSE you have to always implement. the #optional have default implementations so unless you wanna change the behavior its not needed to implement them.
Related
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
Sorry this question may sound "subjective" but I think it should have a pretty definitive answer. I have a class "LocationManager" that I want to manage my Core Location logic. I have two options:
LocationManager has a strong property referencing an instance of CLLocationManager. LocationManager is a delegate of CLLocationManager and receives location updates from it as such.
LocationManager is a subclass of CLLocationManager, and says self.delegate = self so that it can receive its own location updates.
I'm curious which of these options is considered the "right" thing to do, I'm sure that there must a be a preferred way. Thanks!
Subclassing CLLocationManager and setting its delegate to self should not be done because it breaks the contract of CLLocationManager. As the class is currently defined, it has a delegate property. This property serves as a contract which states that you may set this property to some other object, and this object will receive delegate notifications. If you subclass CLLocationManager (let's call it MyLocationManager), and if the delegate property of the object points to itself, then you will most likely create a situation where MyLocationManager only works as promised if the user does not use the delegate property for his own purposes. From a users point of view, MyLocationManager is a CLLocationManager without a usable delegate property. This violates Liskovs Substitution Principle, btw. The question to ask here is: would MyLocationManager still work, if some ViewController class decides to use it and have its delegate property point to itself (the ViewController)?
Furthermore, it is no longer "delegation", if you say self.delegate = self. So I would say it is preferrable to use variant 1.
Thanks for the question.
Yes you can do this with no problem. I've a subclass of UITextField which is its own delegate.
The first option seems right to me because it doesn't make a ton of sense to subclass CLLocationManager (#2). What functionality would you be adding to it? If you're not adding anything to it why subclass?
All you care about is encapsulating the messages about location updates. I'd say you're using the delegate/protocol pattern acceptably in the first case.
And Jef is right, there are times where a subclass of another class can be set as its own delegate. Though you need to be careful about how that object responds to certain messages.
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).
As the title implies, I'm asking if it would be okay to link a single delegate to two different UIViewControllers in my project. I'm trying to link to two different VCs in my project but it's making the first VC's act weird so I'm wondering if I'm doing it wrong?
Sorry if this is a noob question, still new to this.
Nothing wrong with this at all.
A delegate protocol is just a protocol. An object can conform to multiple protocols at the same time (e.g. UITableViewDelegate and UITableViewDatasource).
You might have two view controllers like MyPersonViewController and MyAnimalViewController and they will have delegate protocols like MyPersonViewControllerDelegate and MyAnimalViewControllerDelegate.
You can then just do...
self.personViewController.delegate = self;
self.animalViewController.delegate = self;
The only thing to make sure of is that when you get the call backs from each VC that you don't confuse them. The best way to do this is to use the same pattern as UITableViewDatasource and prefix the methods like...
- (void)personViewController:(MyPersonViewController *)controller gotSomeResults:(NSArray *)results
Or something. Anyway, then you have a completely different set of delegate methods for each controller.
Whenever I create a UI object such as UITextField programmatically, I do this:
txt.delegate = self;
A compiler warning appears and asks me to add UITextFieldDelegate in the .h file.
I noticed though that it makes no difference with or without, the code works fine either way.
But the compiler warning disappears. Why is this?
You don't actually need to set the delegate property on your objects unless you are actually using the delegate methods. For example, if you need to know when the UITextField is about to begin editing. If you don't need to know when these things occur, you don't need to set the delegate.
Looking at it the other way, if you make your class conform to a delegate method (by adding <SomeClassDelegate> in the .h file), and then forget to implement required delegate methods, you'll get a warning from the compiler, and a crash when the app runs (and sends a required delegate message to your object).
To answer your question about not adding UITextFieldDelegate to your .h file, imagine your friend is looking for a French translator. You find a foreign looking man and introduce him. Your friend asks "But can he speak French?" You reply "I don't know". This is your warning.