iPhone: What is the correct usage of viewDidDisappear? - iphone

I'm still very new to Objective C, and I was wondering something regarding viewDidDisappear.
I have an app that plays a sound (using AVAudioPlayer), and I want to stop the sound when the view is switched.
If I do this in my view controller implementation:
- (void)viewDidDisappear:(BOOL)animated {
[self.audioPlayer stop];
}
it works fine. But the small programmer in my brain is saying that I'm not using this correctly.
I'm pretty sure you are supposed to CALL viewDidDisappear with a boolean argument, rather than just specify (BOOL)animated; besides, it would be nice to have some animation in my view switching... then again, that might be a whole different discussion!
So, what am I doing wrong, and how would I correctly use this? Do I have to link the call a button action? Where is the correct play to actually declare the function itself?
Thanks.

I implement viewDidDisappear:(BOOL)animated EXTENSIVELY, along with viewWillAppear, viewWillDisappear and viewWillDisappear The main reason to implement this method is to make your view controller to do something at the event, such as viewDidDisappear You don't call this method, but your app will call your view controller to do what's implemented there. Since this is inherited method, as long as you make sure all the inherited implementation from the super class can be done, it's great to implement viewDidDisappear. So, I suggest you to change your code to be like this:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:(BOOL)animated]; // Call the super class implementation.
// Usually calling super class implementation is done before self class implementation, but it's up to your application.
[self.audioPlayer stop];
}

- (void)viewDidDisappear:(BOOL)animated is a method declaration, not a call of any sort. The method itself is called by UIKit as view controllers are manipulated; you don't need to call it yourself unless you're writing your own code that makes view controllers appear and disappear by directly manipulating the views they control (e.g. if you were rewriting UINavigationController for some reason).
You are doing something wrong, though: you must call [super viewDidDisappear:animated] somewhere in your implementation, or things may break.

The "small programmer" voice in your mind is probably more used to procedural coding, where you call the OS and tell it what to do. Cocoa Touch instead uses an event driven paradigm, where your program has routines (methods) that the OS(framework)calls when it is good and ready. viewDidDisappear is one of those routines. Just sit tight, and wait for the OS to call it (assuming you've set everything up properly.)

viewDidDisappear: is an optional method that your view can utilize to execute custom code when the view does indeed disappear. You aren't required to have this in your view, and your code should (almost?) never need to call it.

Related

iOS: How to know if viewDidLoad got called?

Is there a BOOL or some other way of knowing if viewDidLoad: has been called?
I need to change a view property every time my view has entered active, but if the view hasn't ever been loaded, I don't want to prematurely trigger viewDidLoad:. If there isn't way of easily telling if viewDidLoad: has been called, I'll simply add a BOOL called loaded set to NO in the view controller init, then change the view properties after entered active if loaded is YES or in viewWillAppear: if loaded is NO then set loaded to YES.
Use isViewLoaded. Other than that it does exactly what you want, there's not that much to say about it. The documentation is as simple as:
Calling this method reports whether the view is loaded. Unlike the
view property, it does not attempt to load the view if it is not
already in memory.
Perhaps you should init your UIView in viewDidLoad, and then change it in whichever way you need to inside viewWillLayoutSubviews.
Here's the pedantic answer to this question. If you want to know when viewDidLoad has been triggered, you have to implement viewDidLoad in your view controller
- (void)viewDidLoad
{
[super viewDidLoad];
viewDidLoadCalled = YES; // Not actually the best way to do this...
// Set up more view properties
}
But as Tommy says, you actually need to use isViewLoaded. This gets around the problem of doing a check like
if (!self.view) {
// do something
}
which inadvertently loads the view by virtue of asking about it.
Be aware that by the time viewWillAppear: is called, the view will always have loaded. Also, on older (pre-iOS 6 I think) releases, the view can unload and be reloaded many times over a view controller's lifetime. Refer to the very nice Big Nerd Ranch view lifecycle diagram for the old behavior. It's almost the same in iOS 6+, except that the view doesn't unload under low memory conditions and viewDidUnload doesn't get called:

Timing for add Notification observer in UIViewController subclass

I'm fairly new to Cocoa Touch. Right now I'm trying to subclass UIViewController to provide my custom view. Since I intend to save the content of a UITextField (passcodeField) using NSUserDefaults, I want to be notified whenever the UITextField changes its value.
I've read somewhere that in order to do that I should add the view controller to be an observer of the UITextFieldTextDidChangeNotification notification. However I'm just not sure when to do that. I've considered several options.
In the -loadView method. However, since I'm loading my view using a XIB, I think i shouldn't mess with this method and should instead leave it as-is. (Am I correct on this point, BTW? )
In the -viewWillAppear method. But this method may be called multiple times because the view may be moved out and into the screen without being destroyed and recreated. (Am I correct? ) This will not do any harm to the program but sure doesn't seem like the correct way.
In the initializer of the UIViewController. If I want to add the notification there I must reference the UITextField. By doing this I essentially cause the view to created before it is really needed. Also I think I read somewhere that if the system runs low on memory the offscreen views may be destroyed. Thus I may lose the notification observing if such thing happens, right?
So I'm totally confused right now. Could you guys give me some advice of where to put it? Thanks so much!
Put it in the - (void)viewDidLoad method of your ViewController remember to call [super viewDidLoad]; at the start of your implementation.

What is meaning of calling superview's viewwillappear?

-(void)viewwillAppear
{
[super viewwillAppear:animated];
}
What does mean of calling [super viewwillAppear:animated] and what happen if we not call it?
By using super you are calling the base class version of the method. You will see similar call in init, dealloc, viewDidLoad etc. methods. The reason is in base class's implementation something important may be carried out without which the derived class will not work properly. When you have overridden the method in derived class, you will need to make a call to the base version by using super.
The only situation you will not call base class's method by using super is when you know that you don't need the tasks carried out by base class, in other words you are overriding completely. This is not the situation with viewWillAppear:animated or viewDidLoad etc. So we always call super in these cases.
Apple's documentation for viewWillAppear: just says:
If you override this method, you must call super at some point in your implementation.
It will probably lead to some unexpected behavior if you don't call it. Note that 'at some point' means you don't have to call it first.
The reference clearly states
This method is called before the
receiver’s view is about to be
displayed onscreen and before any
animations are configured for showing
the view. You can override this method
to perform custom tasks associated
with presenting the view. For example,
you might use this method to change
the orientation or style of the status
bar to coordinate with the orientation
or style of the view being presented.
If you override this method, you must
call super at some point in your
implementation.

Delegation, some example of code? How object delegate to other

I would like to gain a better understanding about the delegation. Can somebody please paste a good code sample of delegation and explain how it works?
There is a pretty good example at: http://en.wikipedia.org/wiki/Delegation_pattern#Objective-C_example
In this example, MyCoolAppController creates and object of type TCScrollView, and sets the "delegate" property of the TCScrollView to self. This means that when the TCScrollView calls
[delegate scrollView:self shouldScrollToPoint:to]
it is asking the MyCoolAppController (the delegate of the TCScrollView) to perform some calculations and see if it is ok to scroll. You can say "MyCoolAppController is the delegate of TCScrollView" to describe this; TCScrollView asks MyCoolAppController to do some work on its behalf.
Do you mean .NET or Java or some other language delegate?
A delegate in .NET parlance is nothing more than a function pointer, or in other words a variable that points to a block of executable code. They can be used in may ways. One way is to use them in the context of events. Lets say you have an ASP.NET page and you are using the MVP (Model View Presenter pattern on that page). You want your presenter to be notified of the click event of the save button on the view. You can define an event on the views interface, but in order to subscribe to that event and to take action on it you need to register a method that gets fired when the event is raised. For example:
public class ClassThatRegistersForEvent
{
public void InitializeView(IView view)
{
view.SaveButtonClickedEvent += delegate{
// do stuff in here when the event is raised
}
}
}
public interface IView
{
event System.EventHandler SaveButtonClickedEvent;
}
Here's an answer I wrote explaining delegation: https://stackoverflow.com/questions/1089737#1090170
A delegate is a way to respond to events. In other languages you would probably do this by subclassing. For example, say you have a table view. You could subclass the tableview and override the tableView:didSelectRowAtIndexPath: method, but that would get messy and create an unnecessary subclass (along with the fact that its not reusable) Instead, you create a TableViewDelegate class and tell your table view about it (tableView.delegate). This way, the method will automatically get called when something happens. This is a really clean solution to event-handling.
After you write a few apps that involve delegates (table views are the big ones), you'll get the hang of it.

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
}