Is It possible to track AVAudioPlayer object by using observer? - ios

I followed the documents about how to set up and observer using KVO mechanism
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html
It's suppose to be very easy.
I created an AVAudioPlayer object and I want to track after every change in it's current time.
I use this code to set up the observer:
[_player addObserver:self forKeyPath:#"currentTime" options:NSKeyValueObservingOptionNew context:NULL];
This code to handle the changes:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"currentTime"]) {
//Do something
}}
And this code when the audio ends:
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
// Remove the observation
[_player removeObserver:self forKeyPath:#"currentTime"];}
For some reason the observer doesn't call to the -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
I know that I can use NSTImer and trigger it when the audio starts playing but I'm looking for smoother way to do this.
I also can use AVPlayer object instead and track it by using it's addPeriodicTimeObserverForInterval:queue:usingBlock:
But I don't want to lose all the advantages of the AVAudioPlayer object.
What am I doing wrong with the observer?
Do you have another suggestion how to use AVAudioPlayer and manage tracking after it's currentTime property?
Thanks in advance,

You're doing nothing wrong.
I've tried to do this as well and it just doesn't fire.
I had to use an NSTimer instead that polled the currentTime :(

KVO will fire for the currentTime property on AVAudioPlayer only when a caller changes the value directly. It will not fire when as the audio clip progresses. To track that, you will have to use NSTimer, as has already been suggested by deanWombourne.

Have you tried
//KVO [self setValue:[NSNumber numberWithFloat:currentTime] forKey:#"currentTime"];
I did this when currentTime changing,and the KVO work fine.but it's still need a timer to tell setting value =.=

Related

AVPlayer stops playing when buffer is full and dosent resume

I have a collection view with an AVPlayer inside the cell and the AVPlayer starts playing the AVPlayerItem in a loop when
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
gets called. this works well but the problem is that after the AVPlayer is playing the item a few times the video is no longer shown but i can hear its sound.
I also add an observer for the value #"playbackBufferFull" for each item that is played like that:
[item addObserver:self forKeyPath:#"playbackBufferFull" options:NSKeyValueObservingOptionNew context:nil];
i noticed that when the video stops the observer method of the value #"playbackBufferFull" gets called, first of all i would like to know what causes the buffer the get full, the second and most important is how can i resume the AVPlayer when the video stops;
i tried calling [cell.videoPlayer play]; and to replace the item with a new one and it didnt work, the observer method:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
if ([object isKindOfClass:[AVPlayerItem class]] && [keyPath isEqualToString:#"playbackBufferFull"])
{
//this method is get called when the video stop showing but i can still hear it
//how can i resume the video?
}
}
my solution is :
first add observe for AVPlayerItemPlaybackStalledNotification in viewDidLoad or ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(playerItemDidReachEnd:)
name:AVPlayerItemPlaybackStalledNotification
object:self.avPlayer.currentItem];
-(void)playerItemDidReachEnd:(NSNotification*)noti
{
//thisisn't good way but i can't find the best way for detect best place for resume again.
NSLog(#"\n\n give Error while Streaminggggg");
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self.avPlayer play];
});
}
BUT
maybe you can find the best way to call play method again for resume!
please check do you get AVPlayerStatusReadyToPlay keypatch ?
if you get , you can call play method there.
please notify me about the result

iOS 9: KVO no longer working

I have an observer on a UITextView to detect if its content size is changing:
[_textView addObserver:self forKeyPath:#"contentSize" options:NSKeyValueObservingOptionNew context:NULL];
This code always worked to call the following function, where I do resizing of the UITextView:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
However, in iOS 9, this function is never getting called. What changed in iOS 9 and how do I fix this?
If you do a search for UIKit and KVO Compliance you will see that everyone says you can't rely on it. See this question and this question.
I don't know what changed, but I think you should just subclass UITextView and overload setContentSize: if you want to know when it changes.

Key-value observing doesn't work for zoomScale

I'm stuck with following problem. I have a UIScrollView, _myScrollView, and I want to have another UIScrollView following it's movements. So I'm using key-value observing for the properties "zoomScale" and "contentOffset", but the observeValueForKeyPath:ofObject:change:context: method only report changes in "contentOffset", not in "zoomScale", though the zooming workes fine. (See code snippet below.) What could be the reason for this?
-(void)viewDidLoad {
...
[_myScrollView addObserver:self forKeyPath:#"contentOffset" options:NSKeyValueObservingOptionNew context:NULL];
[_myScrollView addObserver:self forKeyPath:#"zoomScale" options:NSKeyValueObservingOptionNew context:NULL];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ([keyPath isEqualToString:#"zoomScale"]) {
NSLog(#"zoomScale: %#", change); // Never gets called
}
...
}
The zoomScale property isn't KVO compliant. But UIScrollViewDelegate has a scrollViewDidZoom method that you can use to track changes to zoomScale.
UIKit actually doesn't support KVO.
From the docs:
Note: Although the classes of the UIKit framework generally do not
support KVO you can still implement it in the custom objects of your application, including custom views.
It does work sometimes (as you've seen), but support for it is undocumented and inconsistent. Use the delegate methods instead.

Detecting a change in the active camera (front/rear)

I have code that does different logic based on which camera is used such as:
if(aPickerInstance.cameraDevice == UIImagePickerControllerCameraDeviceFront){
// Front camera logic
}else{
// Rear camera logic
}
My issue is that when the switch occurs, front-to-rear or vice versa, I have found no way to tell when the "cameraDevice" property value has changed in order to reevaluate my states. (basically rerun logic blocks to set everything right for the newly selected camera).
When you create your picker, add an observer:
[_picker addObserver:self forKeyPath:#"cameraDevice" options:NSKeyValueObservingOptionNew context:nil];
Then add the handler:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSLog(#"Keypath %# change %#", keyPath, change);
}
change[#"new"] will give you a new value for cameraDevice. You can also just use this to detect a change and trigger your own cameraDevice state check.

Call animation method when UItextField.enabled changes

I've got a set of UITextFields which are enabled or disabled based on an if function (basically only allows 2 to be filled in, then the others are disabled).
I've got 2 methods to fade the background of the UItextFieldFade in and Fade out.
I want the animation to run every time the enabled property of the UITextField changes but don't really know how to track the actual change.
Any help would be great.
Thanks
Add an observer to the text field:
[_textField addObserver: self forKeyPath: #"enabled" options: NSKeyValueObservingOptionNew context:NULL];
You should implement this method:
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *) context;
Where you handle the value change of the "enabled" property.
Documentation: Key value observing.

Resources