iOS - Stopping a Video on Navigation Change - iphone

So here is my dilemma, I have a navigation controller that controls three views. The first view has audio on it, the second view image sequences/videos and the third view will have audio.
How can I make sure that all of those things are ended (or just end them) when someone clicks the "Back" button to go to a lower numbered view?

media player classes, like audio and video, usually have "stop" methods that will do the trick. You can hook in to the viewWill/Did/Appear/Disapper methods on UIViewController to know when a view is/did become(ing) visible/invisible and stop the media playback at that time. I also like to put put "stop" method calls to media players in viewWillUnload and dealloc.

Make yourself the delegate of the UINavigationController and implement this:
- (void)navigationController:(UINavigationController *)navController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
// Pseudo Code Here
[audio stopPlaying];
}

Look at UINavigationControllerDelegate. It has needed methods.

Related

Local notifications and storyboards

I'm wondering what would be the best way to accomplish my goal. I have an iPhone app that is using storyboards and has a tabbar controller as the root view. Under one of the tabs I need to show a view controller that is embedded in a navigation controller and is about 3 slides deep when a local notification is pressed.
Any ideas of the best way to do this? Going to continue with trying to implement this in a clean way and I will post if no one has a response, but some help in the right direction would be appreciated. Thanks.
This was the method I was after:
(void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated
And since I wanted to use existing viewcontrollers that had layouts for my view from the storyboard I pulled them in using this and initialized what I need. Help this helps someone else in the future.
(id)instantiateViewControllerWithIdentifier:(NSString *)identifier
I would use the userInfo property on the UILocalNotification class. Setup a string with the name of the controller you want to show.
Catch the notifications with:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
In the AppDelegate. Then search for the string you save on the UILocalNotification and use the next method in the UINavigationController:
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
In order to show the appropiate viewcontroller. If you want your app to show always the same view controller you don't need to setup the userInfo, you only need to implement the UINavigationController method above.
Hope it helps.

Preventing view from unloading in iOS SDK?

I've built an app that uses a UITableView inside a UINavigationController, inside a UITabBarController. Every entry in the UITableView opens up a view that contains some basic text, buttons, but most importantly, an MPMoviePlayerController that plays audio when started. A user can click this MPMoviePlayerController and continue to browse around the rest of the app (different tabs, or moving back in the navcontroller, opening other views from the tableview) and continue to hear the audio.
I'd like the user to be able to return to the view with the active MPMoviePlayerController at any time. I understand how I would go about allowing the user to return to a certain view from any view, but I'm struggling with how to prevent that view from being reloaded when the user tries accessing the same view.
Is there any way I can save a view in memory? Or save the active MPMoviePlayerController as some type of global object, so that I can at least access that from anywhere?
I appreciate any and all help. Thanks!
I'd recommend you create a property for the MPMoviePlayerController in your app's UIApplicationDelegate (which you can then access from anywhere in the code with [UIApplication sharedApplication].delegate but you will need to cast to your UIApplicationDelegate subclass).
When you come to enter the screen which plays content, check whether your movie player property in the app delegate is nil, if it is create it, otherwise re-use it.
Don't forget to release the reference to your MPMoviePlayerController when the media stops playing, or when the media has already stopped and you get a memory warning or when your app shuts down.
The down side of this approach is it causes coupling between most of your view controllers and your app delegate. You could mitigate this with the use of a protocol however.
You should simply retain it. Like this [myView retain] and keep a pointer to it in where you need. When you want myView to appear, just add it as a subview to current visible view like[myController.view addSubview:myView].
Hope that will help, Good luck!
I've found that even adding a retain doesn't do the trick. I've actually found the best success with overriding the setView (since part of unloading the view involves calling setView:nil. I have a BOOL that gets set the FIRST time the VC loads and once thats set it will never allow setView to be called again.
- (void) setView: (UIView*) view{
NSLog(#"MainViewController: setView");
// this is our attempt to stop iOS from unloading our view.. when iOS tries to unload your view they call setView:nil.. so, no!
if(!viewDidAppear) [super setView:view];
}
A little bit of a hack, but you can override setView: in your subclass so that it never allows to set the view to nil:
-(void)setView:(UIView *)view
{
if (view == nil) return;
[super setView:view];
}

touch response event ios4

I added a ViewController to an app for ad banner support. The app was based on a UINavigationController so I added the ViewController as a subview to the UINavigationController. Now the area of the ad banner does not recognize when it is touched to open the ad in safari. I have tried to make the ViewController becomeFirstResponder but that doesn't work. Does anyone have any thoughts on how to fix?
you say you added it as a subview, but I hope you mean you pushed it with
- (void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
Your view controller can respond to events because it is a UIResponder. UIView and therefore most visual controls like UIButton, UISlider etc. inherit from UIResponder also - but they implement specific actions based on user interaction.
If you really want to intercept events in a UIViewController you will need to handle touchesBegan/Moved/Ended events. More likely you have at least a UIWebView or UIImageView in the view controller if it is displaying something you want to click on.
If UIWebView you'll need a UIWebViewDelegate implementing
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
will let you know what links are being opened.
If a UIImageView you will also need to set the property userInteractionEnabled before you see any touch events.
If you're dealing with iAd's AdBannerView class, that inherits from UIView also, so comments for UIImageView apply. HOWEVER ADBannerViewDelegate is a requirement for built-in interaction support - just like UIWebViewDelegate, you must implement a permission/notification function,
- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave

MPMediaPickerController in one view and the MPMediaPlayback in another view. How to?

Basically I have a three view stack. In the last view I got a MPMediaPickerController that lets the user pick a song from his/her library. The song is to be played later from the first view. How can I tell the player (in the first view) what should be played?
One possibility would be to send a notification and include the MPMediaItemCollection as the object maybe?
Is this a/the correct way or do you have other smarter suggestions?
I ended up using NSNotification and attaching the MediaItemCollection as userInfo.
Use the MPMediaPickerController delegate:
in your third view controller set the MPMediaPickerController delegate to be your first view. Implement the delegate callback functions in your first view controller.

viewWillAppear not called in UITableViewController?

I have a couple of UITableViewController classes and I just noticed that these methods aren't being called:
-(void)viewWillAppear:(BOOL)animated;
-(void)viewDidAppear:(BOOL)animated;
I read in http://discussions.apple.com/thread.jspa?threadID=1529769&tstart=0 that I would have to call those methods myself when pushing view controllers, but that's strange, since it works for anything but UITableViewController.
Also makes it a bit of an issue when I need to have a UITableViewCell deselected in the UIViewController that pushed the UITableViewController.
I can't find it in the documentation, but I think this might be because you are using a UINavigationController.
How about setting the UINavigationController's delegate property and then implementing UINavigationControllerDelegate? It provides two optional methods:
– navigationController:willShowViewController:animated:
– navigationController:didShowViewController:animated:
For example, navigationController:willShowViewController:animated: might look something like this:
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
if ([viewController isKindOfClass:[UITableViewController class]]) {
[viewController viewWillAppear:animated];
}
}
Anyway, this will get you the behavior you want without having to hack calls to viewWillAppear: all over your project.
Did anyone resolve this because the original post is correct - simply using UITableViewController and pushing the table view of that controller onto the navController does NOT trigger these methods despite the fact that it should. I have a series of UITableViewControllers and table views that are pushed and popped to display hierarchical data - nothing fancy, but the "viewWill/Did/Appear/Disappear" methods are never called. Only the viewDidLoad and viewDidUnload are called.
There must be a wiring problem in both our setups, but simply pushing a view into the navigationController should be all that is required (?) - hard to believe that this could have gone unnoticed as a fundamental bug this long.
?
These two methods are called by default to notify for the changes. UITableViewController is a subclass of UIViewController, so there will be the same behavior. You can see more in the View Controller Programming Guide
The viewWillAppear: and viewDidAppear: methods give subclasses a chance to perform any additional actions related to the appearance of the view.
How do you know that these methods are not called? Can you provide some more codes, or at least you test them with a NSLog() to see if there are some messages printed.
I'm seeing the same problem. I have a simple UIView from the IB and I do a addSubview with a class that extends UITableViewController.
I can see the view of the TableViewController without problems in my application, but the viewWillAppear function is never called in this situation.
Well, the discussion linked from the question has the answer right in it. UINavigationController needs to receive the "viewWillAppear" message in order for it to send those messages to the view controllers you push onto it.
So ironically if you don't do what Apple recommends, and you subclass UINavController for your view controller, then everything works great.
However, if you just create a UINavController inside of your view controller, then you need to implement "viewWillAppear", "viewDidAppear" and so on and forward those to your nav controller.
Note that this is especially important if you're using Three20, because its view controller hierarchy expects the "viewWillAppear" message to be received. If its not you can end up with TTTableViews that don't draw.
The same can occur if you use a UITabViewController. You need to force the viewWillAppear call by implementing either the UITabViewControllerDelegate or UINavigationControllerDelegate callbacks
This explanation may help: http://www.mlsite.net/blog/?p=210