iPhone: Is it safe to call textViewDidChange? - iphone

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.

Related

How does a delegate method know when to be called

I'm just wondering how exactly does a delegate method know when to be called? For example in the UITextFieldDelegate protocol the textFieldDidBeginEditing: method is called when editing begins in the textfield (provided I implemented this method).
So how exactly does the code to detect when to call textFieldDidBeginEditing:? Does the system just check if textFieldDidBeginEditing: is already implemented and if it is it runs that method? Is there something under the hood that I'm not seeing?
Exactly.
I can't vouch for how Apple's framework code is implemented under the hood, but an exceedingly common refrain is:
if ([[self delegate] respondsToSelector:#selector(someInstance:didDoSomethingWith:)]) {
[[self delegate] someInstance:self didDoSomethingWith:foo];
}
This allows you to have optional delegate methods, which appears to be your question.
The code doesn't 'detect when to call' a delegate method. The textField receives an event, and calls the method on it's delegate (which has the textFieldDidBeginEditing: method implemented).
In short, when you tap the textfield to start editing, the textField says 'oh, I'm editing now!' and internally calls [self.delegate textFieldDidBeginEditing:self], where the delegate is the instance in which you've set to be the delegate (usually a UIViewController subclass)

Objective-C Runtime: Swizzled method name?

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.

Programmatically dismissing a UIAlertView on iOS 5 doesn't call didDismiss delegate method

I'm running into a problem where 9 times out of ten, when I call UIAlertView's dismissWithClickedButtonIndex:animated:, the delegate method alertView:willDismissWithButtonIndex: is not called. Is anyone else running into this problem? I'm about to file a bug with Apple but I'm curious to see if anyone else has run into this issue and figured out any workarounds.
To ensure a consistent behavior across iOS4 and 5, you could just remove the UIAlertView's delegate just prior to calling its dismissWithClickedButtonIndex:animated: method, then manually invoke the delegate method. e.g.
- (void)somethingDidHappen {
id<UIAlertViewDelegate> delegate = myAlertView.delegate;
myAlertView.delegate = nil;
// now, we know the delegate won't be called...
[myAlertView dismissWithClickedButtonIndex:0 animated:NO];
// ...so we call it ourselves below
[delegate alertView:myAlertView clickedButtonAtIndex:0];
}
(That code isn't tested, but you get the point.)
Delegates of UI objects are only called when the user performs an action. Apple assumes that when you do something from code, you already know what you're doing and you don't need to be informed. That applies to all delegates (scrolling delegate methods of UIScrollView vs. code-scrolling, Table View manipulation, ...)
Anyway, what button index should the delegate be called with?.. there is no one when you dismiss programmatically
According to Why doesn't dismissWithClickedButtonIndex ever call clickedButtonAtIndex? the problem is that a different method is being called. However, that doesn't explain why you get erratic calls. On the devices I tested the dismiss method gets called correctly, so I only redirect it to the click version.
Maybe you should file a bug with Apple if you continue seeing the erratic behaviour.
There are alertView:clickedButtonAtIndex:, alertView:didDismissWithButtonIndex: and alertView:willDismissWithButtonIndex:. The method that you're referring to (clickedButtonAtIndex:) is only called when the user explicitly taps on a button on your alert view (hence 'clicked').
Programmatic calls via dismissWithClickedButtonIndex:animated: to dismiss the alert does not seem to call alertView:clickedButtonAtIndex:.
So, if you need some behavior to be always triggered upon the dismissal of the alert view—whether it was triggered by the user tapping on a button or triggered programmatically—then using the didDismissWithButtonIndex: and willDismissWithButtonIndex: makes more sense.

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.

Do I always have to call [super viewDidLoad] in the -viewDidLoad method?

In Apple's scrollView example they don't call that. I always thought that's a must. Why should I call that anyways?
If you are overriding the method you should still call the method in the super. Even if the super class is not doing anything with it today, Apple might one day change the implementation and your code will mysteriously stop working. If you really don't need to do anything in that method, leave it out of your code entirely, and the super's method will run as usual, without any intervention on your part.
No, you don't need to call [super viewDidLoad]. Edit: But read below, because I think you definitely should.
Let's be real here: Apple is not going to break thousands of apps, including those based on their published sample code, by deciding an event they're not currently handling suddenly needs to do something that developers may or may not want to stop and it's critical that if you don't need different behavior you not stop the event.
Edit: Having watched how Apple handles compatibility for an extra year, I now recommend learning and using the correct pattern. While I doubt your application binary will ever suddenly stop working, it's clear that the iPhone detects which SDK your binary was built against and modifies some OS behaviour based on this.
Apple might one day require a particular pattern be followed on some future SDK. This would not affect you until you rebuild with the latest Xcode + SDK, but then you'd get these breaks without any source code changes. Learn and follow the pattern to be safe.
As Markus says, UIViewController doesn't do anything in its viewDidLoad method, so you don't have to call it. However, it's a good habit to get into, in case you change your inheritance structure and suddenly the class that used to inherit from UIViewController now inherits from something that does do something in the viewDidLoad method.
Lets say you have 2 class, a Parent and a Child. Child inherits from Parent. They have a method called greet which returns a string.
Here is what the parent method looks like:
Code:
-(NSString *)greet {
return #"Hello";
}
We want the child to learn from his parents. So we use super to say greet how Mommy would greet, but with our own little additions too.
Code:
// Inherits from Parent
-(NSString *)greet {
NSString *parentGreeting = [super greet];
return [parentGreeting stringByAppendingString:#", Mommy"]
}
So now Parent greets "Hello", and the Child greets "Hello, Mommy". Later on, if we change the parent's greet to return just "Hi", then both classes will be affected and you will have "Hi" and "Hi, Mommy".
super is used to call a method as defined by a superclass. It is used to access methods that have been overriden by subclasses so that the class can wrap its own code around a method that it's parent class implements. It's very handy if you are doing any sort of inheritance at all.
Apple's documentation for viewDidLoad does NOT state that you should call [super viewDidLoad], so I would go with what Apple's says. Note, however, that for other similar methods like viewDidAppear, you must call [super viewDidAppear].
You don't have to call the [super viewDidLoad]
As far as I know, the viewDidLoad in the superclass (UIViewController) is only an empty function that gets called when the ViewController gets initialized with a nib-file.
So if you need to do any initializing, you should override this function and put your code there.
Just noticed that the static analyzer of Xcode 6 issues a warning if you do not call super in these functions. So it seems Apple now definitely wants us to call it.
Although in xCode 7 Beta/Swift 2 super.viewDidLoad won't compile. The error says it's only available in osx 10.10 and the auto-fix does this
if #available(OSX 10.10, *){
super.viewDidLoad()}
else
{
// Fallback on earlier versions
}
// My code
}