I've got an application with a navigation tree. Somewhere there is an audio player with an mp3.
UITabViewController // controlled by AppDelegate.m
-> UINavigationController
-> UITableViewController // controlled by TableViewController.m
-> UIViewController // with my AVAudioPlayer controlled by AudioViewController.m
In AudioViewController.m I have all my audio engine so i play/pause/stop it, and even kill it when pressing back button (using viewWillDisappear etc) - it plays only in this one view, not another, and it's good.
However there is an issue when i press home button while playback is on. It stops, but after going back to my app, it plays again from remembered time stamp.
I tried all this:
- (void)viewDidUnload
{
[super viewDidUnload];
[self audioStop:self];
}
- (void)viewWillDisappear:(BOOL)animated
{
[self audioStop:self];
[super viewWillDisappear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self audioStop:self];
}
- (void)viewWillUnload
{
[self audioStop:self];
[super viewWillUnload];
}
- (void)awakeFromNib
{
[super awakeFromNib];
[self audioStop:self];
}
But nothing happens.
Now i know that to manage if home button was pressed, i need to use applicationWillResignActive method from AppDelegate, but i have totally no idea how do i stop my audioplayer from here. I'm quite new to iOS and i'm not familiar with how delegates work, so please help me work this out.
Let you AppDelegate hold a reference for you UIViewcontroller some how and call it. Make sense?
AppDelegate
|
v
TableViewController (#property)
|
v
UIViewController (#property)
|
v
AudioPlayer (#property) --> [ stop];
Edit:
#interface TableViewController : UIViewController
{
AudioPlayer * audioPlayer;
}
#property(nonatomic, retain) AudioPlayer * audioPlayer;
... // other stuff
#end
#implementation TableViewController
#synthesize audioPlayer;
... // other stuff
#end
This way you can access the audio player from TableViewController object. If you hold TableViewController object this way it should be easy for you.
[tableViewController.audioPlayer someMethod];
something like that ..
When home button was pressed, you need to use applicationWillResignActive method from AppDelegate, How we can use this method , i will show you. You need to use NotificationObeserver in your view controller.
How To add NotificationOberserver
NotificationCenter.default.addObserver(self, selector: #selector(self.application_resign_active(notification:)), name: NSNotification.Name.UIApplicationWillResignActive, object: nil)
Now You can stop sound in this function : Like This
func application_resign_active(notification : NSNotification)
{
if my_audio_player.isPlaying{
print("Stop")
my_audio_player.stop()
}
}
my_audio_player is an instance of AudioPlayer
var my_audio_player = AVAudioPlayer()
You can also Check My Video , how i do this : https://www.youtube.com/watch?v=BxmhTAd1SU4
Related
Ive set a music track to play within the ViewController.h and .m files as shown below. I want to stop this when a new scene is loaded. (.h):
#interface ViewController : UIViewController<AVAudioPlayerDelegate>{
AVAudioPlayer *startingMusic;
}
#property (nonatomic, retain) AVAudioPlayer *startingMusic;
#end
and then .m
#synthesize startingMusic;
- (void)viewDidLoad
{
[super viewDidLoad];
NSString *music = [[NSBundle mainBundle] pathForResource:musicTrack ofType:#"mp3"];
startingMusic=[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:music] error:NULL];
startingMusic.delegate=self;
startingMusic.numberOfLoops=-1;
[startingMusic play];
}
I then try and stop this from playing when the new scene loads is a different class called PlayLevel.m in an init method using this code.
ViewController *test = [[ViewController alloc] init];
[test.startingMusic stop];
However the music just continues to play when the new seen loads. Any suggestions?
When you do ViewController *test = [[ViewController alloc] init]; you created the new ViewController instance, it's mean you now have two ViewController's objects in the memory.
What you really need to do is call stop on your current one.
If you want to stop music from another controller which has no connection to your ViewController you can try doing this via notifications.
For example:
in your ViewController.h file, after imports:
static NSString * const kStopMusicNotificationName = #"kStopMusicNotificationName";
in your ViewController viewDidLoad:
[NSNotificationCenter.defaultCenter addObserverForName:kStopMusicNotificationName object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self.startingMusic stop];
}];
and when you need to stop music:
[NSNotificationCenter.defaultCenter postNotificationName:kStopMusicNotificationName object:nil];
You're going about this the wrong way around, you should really be stopping the music within ViewController and not from another class. ViewController should be self contained where ever possible.
How are you loading the 2nd scene? I imagine you're using a Segue?
If you are using a segue you can override the function -prepareForSegue which is a UIViewController function. Within -prepareForSegue stop the music then.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Stop Music
}
I have an app that presents images and/or movies in sequence. The problem is, I cannot dismiss one movie player and then present another. If I try, I get the message "Warning: Attempt to present MPMoviePlayerViewController on MyViewController while a presentation is in progress!" Unlike other animated present/dismiss methods, there is no completion handler, nor a non-animated version of present/dismiss.
Here is a simplified version of my code:
-(void) play
{
[[window rootViewController] presentMoviePlayerViewControllerAnimated:player];
[[_player moviePlayer] play];
}
-(void) videoNotification:(NSNotification *) notification
{
if([notification.name isEqualToString:MPMoviePlayerPlaybackDidFinishNotification])
{
[[window rootViewController] dismissMoviePlayerViewControllerAnimated];
[_canvasManager showNextCanvas]; //this calls play on the next canvas
}
}
Any thoughts/hints on how to achieve my goal?
After looking at dismissViewControllerAnimated:completion:, I was able to create a completion handler by creating a subclass of MPMoviePlayerViewController and overriding -(void)viewDidDisappear. viewDidDisappear gets called at the end of dismissMoviePlayerViewControllerAnimated.
#interface MyMoviePlayerViewController : MPMoviePlayerViewController
{
void (^_viewDidDisappearCallback)(void);
}
- (void)setViewDidDisappearCallback:(void (^)(void))callback;
#end
#implementation MyMoviePlayerViewController
- (id) initWithContentURL:videoPath
{
self = [super initWithContentURL:videoPath];
_viewDidDisappearCallback = nil;
return self;
}
- (void)setViewDidDisappearCallback:(void (^)(void))callback
{
_viewDidDisappearCallback = [callback copy];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
if(_viewDidDisappearCallback != nil)
_viewDidDisappearCallback();
}
#end
I have a question about CvPhotoCamera (OpenCV) in the iOS App.
I have a myViewController1: in this viewController I push a mySecondView controller.
In this second View Controller I use CvPhotoCamera:
I have a UIImageViewController.
In viewDidLoad I have this code:
- (void)viewDidLoad
{
[super viewDidLoad];
_photoCamera = [[CvPhotoCamera alloc] initWithParentView:imageView];
_photoCamera.defaultAVCaptureSessionPreset = AVCaptureSessionPresetPhoto;
_photoCamera.defaultAVCaptureVideoOrientation = AVCaptureVideoOrientationPortrait;
[_photoCamera setDefaultAVCaptureDevicePosition:AVCaptureDevicePositionBack];
_photoCamera.delegate = self;
[_photoCamera start];
}
in viewDidDisappear I have this code:
- (void) viewDidDisappear:(BOOL)animated
{
[_photoCamera stop];
}
I use CvPhotoCamera to take a photo from camera using the method:
- (IBAction)actionStart:(id)sender;
{
[_photoCamera takePicture];
}
The my problem is this:
When I push this second ViewController and I tap on back button on Nav bar I have some memoryWarning and the app crashes ..always!!!
I used also the profile Xcode tool to manage memory allocation or memory leak but I do not see anything strange.
Is correct this use of CvPhotoCamera obj?
I am new to iOS app development. I want to create a Calculator App in iOS that has split view. The left side is the "History" Feature in Scroll View and the right side is the calculator itself. Now, regarding the History feature of this app, I am thinking that my program needs to recognize what has been pressed and display it on the Scroll View when the Equal (=) button is pressed. Do you have any idea how will this go on Objective-C? I am using XCode 4.5 and iPhone Simulator 6.0.
Thanks in Advance!
If you want to communicate/send data between views or view controllers there are several options.
If you try to communicate/send data between views and you have reference to both views you can simply call the methods from your views for example
LeftView.h
#interface LeftView : UIView {
//instance variables here
}
//properties here
//other methods here
-(NSInteger)giveMeTheValuePlease;
#end
LeftView.m
#implementation LeftView
//synthesise properties here
//other methods implementation here
-(NSInteger)giveMeTheValuePlease {
return aValueThatIsInteger; //you can do other computation here
}
RightView.h
#interface RightView : UIView {
//instance variables here
}
//properties here
//other methods here
-(NSInteger) hereIsTheValue:(NSInteger)aValue;
#end
RightView.m
#implementation LeftView
//synthesise properties here
//other methods implementation here
-(void)hereIsTheValue:(NSInteger)aValue {
//do whatever you want with the value
}
AViewController.m
#implementation AViewController.m
//these properties must be declared in AViewController.h
#synthesise leftView;
#synthesise rightView;
-(void)someMethod {
NSInteger aValue = [leftView giveMeTheValuePlease];
[rightView hereIsTheValue:rightView];
}
You can use the delegate pattern (very very common in iOS), a short and basic example of delegate you can find in one of my SO answer at this link
You can also use blocks to communicate/send data between views/view controllers but this topic I think you will use a little bit later and for you will have to google a little bit in order to get a basic idea of iOS blocks.
Here is the solution for this requirement.
In my case.. I have 2 buttons in viewcontroller. When I click on those buttons I had to display popover. For this I had to detect which button is clicked in PopoverController(AnotherViewController).
First I have taken #property BOOL isClicked; in AppDelegate.h
And in AppDelegate.m #synthesize isClicked; (synthesized it) and in
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
isClicked = FALSE;
}
Now in ViewController.m where action is implemented for buttons changed like this,
- (IBAction)citiesButtonClicked:(id)sender
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
delegate.isClicked = FALSE;
}
- (IBAction)categoryButtonClicked:(id)sender
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
delegate.isClicked = TRUE;
}
PopoverViewController (AnotherViewController) in -(void)viewDidLoad method
-(void)viewDidLoad {
{
AppDelegate *delegate = [UIApplication sharedApplication].delegate;
if (delegate.isClicked)
{
delegate.isClicked = FALSE;
NSLog(#"popover clicked");
}
else
{
delegate.isClicked = TRUE;
isClicked = YES;
}
}
I hope it helps. Let me know if you need any help.
I'm using the TapJoy SDK for a game application on iOS. The SDK has a way to display a view on top of the application: http://knowledge.tapjoy.com/integration-8-x/ios/pb/featured-app
I can give the function a UIVIewController argument, so I can manage the show/hide by myself.
I have created the following UIViewVontroller:
#interface MyViewController : UIViewController
- (void) viewDidLoad;
- (void) viewDidUnload;
- (void) viewWillLoad;
- (void) viewWillUnload;
- (void)viewWillAppear:(BOOL)animated;
- (void)viewDidAppear:(BOOL)animated;
- (void)viewWillDisappear:(BOOL)animated;
- (void)viewDidDisappear:(BOOL)animated;
#end
#implementation MyViewController
- (void) viewDidLoad
{
self.view = GRAPHIC_SYSTEM::GetGlView();
NSLog(#"viewDidLoad");
}
- (void) viewDidUnload
{
NSLog(#"viewDidUnload");
}
- (void) viewWillLoad
{
NSLog(#"viewWillLoad");
}
- (void) viewWillUnload
{
NSLog(#"viewWillUnload");
}
- (void)viewWillAppear: (bool)animated
{
NSLog(#"viewWillAppear");
}
- (void)viewDidAppear:(BOOL)animated
{
NSLog(#"viewDidAppear");
}
- (void)viewWillDisappear:(BOOL)animated
{
NSLog(#"viewWillDisappear");
}
- (void)viewDidDisappear:(BOOL)animated
{
NSLog(#"viewDidDisappear");
}
#end
When I'm notified by TapJoy that a feature app is available, I show it using my view controller:
[TapjoyConnect showFeaturedAppFullScreenAdWithViewController: [[MyViewController alloc] init]];
The TapJoy view is successfully displayed on top of my game.
There are 2 problems:
Only the viewDidLoad log is printed in the console. None of the other log messages are printed
I would like to know when the user has closed the TapJoy view, so I can add some processing at that time, but none of the other functions of the view controller are called.
I've seen here on SO that some users recommend to use the Notifications. Unfortunately, as I don't have access to the source code of the TapJoy SDK, I need to find another way.
Do you have any ideas?
Thanks in advance
Mike
Well I could fix the issue by creating a custom UIView, which I set as the UIViewController view.
Next, I have then overriden the willRemoveSubview function of this custom view.
And with the viewDidLoad function of the UIViewController, I know when the view is displayed, AND when the TapJoy view is removed, so I can remove my custom view too.