Objective-C Runtime: Swizzled method name? - iphone

In an attempt to Detect backspace in UITextField,
I've tried subclassing UITextField and overriding -[UIKeyInput deleteBackward], but it never gets called. So, I'm suspecting UITextField swizzles deleteBackward to another method name.
Using the Objective-C Runtime, how can I determine which method name deleteBackward has been swizzled to? Then, how can I change the implementation so that UITextField will call [self.delegate textField:self shouldChangeCharactersInRange:NSMakeRange(0, 0) replacementString:#""] when the delete key is pressed when it's empty.
Also, will this kind of metaprogramming get my app rejected from the App Store?

Swizzling doesn't change the name of a method. If it did, it would be impossible to call the method, since the runtime finds the implementation using the name. All it does is change the address of the code which is run when you call a specific method.
My guess as to why the deleteBackward method isn't being called is that the input system is using a method from the more complicated UITextInput protocol instead, most likely replaceRange:withText:. Try swizzling that and performing your call when the text argument is an empty string. Also make sure your swizzling function doesn't return an error.

Related

declaring methods in my header file

easy question to ask, but not really sure what to search for to find an answer for this one.
do I have to declare the method
- (void) applicationWillResignActive:(NSNotification *) notification;
in my header file? I'm trying to build my first app and im just going through trying to clean up my code.
Thanks!
No you don't have to. These are methods that will allow you to perform certain actions in some conditions, in the case of this one is when your application is about to go to the background. If you don't implement it nothing will happen. It is the same as with "viewWillAppear" and so on.
Also those methods only have to be implemented in the .m file since they come from the parent class. Since you are probably placing it in an object that comes from an UIViewController subclass.
The method applicationWillResignActive: is an optional method in the UIApplicationDelegate protocol. Your app delegate should already have declared that it conforms to that protocol in its header. So since it is already declared you don't have to declare it again.

iPhone: Is it safe to call textViewDidChange?

I'm looking at code in a UIViewController that conforms to the UITextViewDelegate protocol and has an instance variable called someTextView.
someTextView.text = #"some text";
[self textViewDidChange:someTextView];
Is that safe? That doesn't look Kosher to me. Is it even necessary to call textViewDidChange:? Won't it get called automatically by someTextView.text = #"some text"?
I'm debugging this error iPhone Objective-C: Keyboard won't hide with resignFirstResponder, sometimes
read the discussion of textViewDidChange:
Discussion
The text view calls this method in response to user-initiated changes to the text. This method is not called in response to programmatically initiated changes.
If it's safe and a good idea to call (UIView-) delegate methods manually depends on the code inside of the method. Sometimes there are valid reasons to do this.
But your bug is most likely not caused by this snippet.

What does obj.delegate=self mean?

What does it actually mean to set the delegate of a textfield?
For example: txtField.delegate = self
"In short, that you are receiving calls from the txtField. You are setting the object 'self' as the delegate for txtField."
"That means that your 'txtField' will receive events from itself
These two answers essentially mean the same thing. But seemingly contradictory. But the first makes more sense to me. I can see why a beginner gets confused, I've been there!
Basically one is the caller one is the receiver Think of it as a chef in a kitchen call his assistant to cut up some onions. In this particular case, txtField is the chef, "self" is the assistant. txtField orders self "Do this, this and this!" Like it or not the assistant has to oblige cuz he has wife and kids to feed. :)
It means that self will be the recipient of certain method calls that are made in response to actions on the text field.
In short, that you are receiving calls from the txtField. You are setting the object 'self' as the delegate for txtField.
Delegating is a programming pattern that is widely used in Objective-C.
The basic idea is let an object delegate some tasks to another object. For example, your UITextField object delegate some tasks to your view controller. In this case, your UITextField object becomes a delegating object, and the view controller the delegate of the UITextField object. The delegating object sends certain messages to its delegate in order to get necessary information, or to notify certain events, etc.
That means that your 'txtField' will receive events from itself (kind of a weird example, maybe a larger source code section could be provided?)
For some of its methods, the textfield (any object in a class using the delegation pattern) is going to try to call some other object to so that that object can customize some of the textfield's behaviors. The object that the textfield will try call is called it's delegate. The delegate is initially set to nil, so, by default, no customization happens.
If a class has a line of code like: textfield.delegate = self; then it says that this object in this class wants to get called to handle the textfield's customization for certain of the textfield's defined delegate methods.
It means the actual class where 'txtField.delegate =self' is called will receive callsbacks from events. This is often a convenient way to do things.

Using an IBAction method when it is not called from an action?

Are there any issues when using IBAction when it is not actually called from a user's action?
If you have an action like
-(IBAction)sayHello:(id)sender;
You can call it from within your class like:
[self sayHello:#"x"]
The #"x" doesn't do anything, it just fills in for the sender.
You can actually create an IBAction method without (id)sender
-(IBAction)sayHello;
and call it from both user's actions and from within the code, but then you won't get any useful sender info from the interface. What's the 'correct' way of filling in for the sender, when calling from the code? And can you create sender info to send when it's called from within the code?
Just trying to figure it out.
I think a good practice for OOP is to refractor the method
-(IBAction)sayHello:(id)sender;
to another method called: -(void)sayHello;
and inside the method
-(IBAction)sayHello:(id)sender {
[self sayHello];
}
If other methods want to call the sayHello:(id)sender action to do some job, it can call the sayHello. The method name should make sense for the client to call it without a problem or work around. It will help you when you have to test or debug
The sender should be a UI component. So if in your class you have, say, a UIButton...
UIButton *button;
Then you can just send it as parameter to the action:
[self sayHello:button];
Insider the method, no matter if it is called from the UI or in some simulated way, you can have some logic to detect who the sender is, and behave differently based on that. This way, multiple buttons or other components can reuse the same action method.
Unless you're actually making use of the sender parameter (see Jaanus's answer for more on that), you're fine with passing nil for it when calling the method from code.

drawTextInRect on UITextField not called

I'm trying to implement the answer to this SO question. The problem is: -[drawTextInRect] is apparently not called, and setting the shadow in -[drawRect] doesn't make the UITextField's text shadowed.
Another weird thing is that even if my subclass implementations of -[drawTextInRect] and -[drawRect] are completely empty (not even a call to super), the textfield's text is drawn.
This is a bug in the UITextField API documentation. The documentation indicates that overriding drawTextInRect: can be used to customize behaviour. This is not the case.
In fact, drawTextInRect: will never be called on an UITextField (drawPlaceholderInRect: will be called neither by the way).
See also http://discussions.apple.com/thread.jspa?threadID=1727596.
Overriding the method on UILabel works though.
I guess the method you are looking for is:
- (CGRect)textRectForBounds:(CGRect)bounds
or possibly
- (CGRect)editingRectForBounds:(CGRect)bounds
I note that -[drawTextInRect] is called once when the UITextField loses focus. Not what I wanted.
UITextField does not respond to a - drawTextInRect: message. The code on the page you reference subclasses a UILabel not a UITextField, which is why it didn't work for you.
If you don't call super, the compiler might be removing the method during optimization of your code. Effectively meaning that UILabel's implementation is getting called.
Update:
If you are using a nib to create the textfield, be sure you have set the class of the textfield in the nib to your custom subclass, otherwise your custom code will not be called.