ios AVPlayer 已被释放,而键值观察者仍在向其注册
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26256982/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
AVPlayer was deallocated while key value observers were still registered with it
提问by Mihir Oza
I am creating a simple media player app. My App is crashed when first link is played and I clicked second link in uitableview.
我正在创建一个简单的媒体播放器应用程序。我的应用程序在播放第一个链接时崩溃,我在 uitableview 中单击了第二个链接。
- (void)viewDidLoad {
[super viewDidLoad];
arrURL = [NSArray arrayWithObjects: @"http://yp.shoutcast.com/sbin/tunein-station.pls?id=148820", @"http://www.kcrw.com/pls/kcrwmusic.pls",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=175821",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=148820",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=70931",nil];
url = [[NSURL alloc] init];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrURL count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
}
cell.textLabel.text = [arrURL objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedSongIndex = indexPath.row;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:indexPath.row]];
[self setupAVPlayerForURL:url];
[player play];
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (IBAction)btnPlay_Click:(id)sender {
[player play];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
}
- (IBAction)btnPause_Click:(id)sender {
[player pause];
}
- (IBAction)btnStop_Click:(id)sender {
[player pause];
}
-(void) setupAVPlayerForURL: (NSURL*) url1 {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url1 options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:anItem]; **//Application Crashed**
[player addObserver:self forKeyPath:@"status" options:0 context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:@"timedMetadata"])
{
AVPlayerItem *item = (AVPlayerItem *)object;
NSLog(@"Item.timedMetadata: %@",item.timedMetadata);
NSLog(@"-- META DATA ---");
// AVPlayerItem *pItem = (AVPlayerItem *)object;
for (AVMetadataItem *metaItem in item.timedMetadata) {
NSLog(@"meta data = %@",[metaItem commonKey]);
NSString *key = [metaItem commonKey]; //key = publisher , key = title
NSString *value = [metaItem stringValue];
NSLog(@"key = %@, value = %@", key, value);
if([[metaItem commonKey] isEqualToString:@"title"])
{
self.lblTitle.text = [metaItem stringValue];
}
}
}
if (object == player && [keyPath isEqualToString:@"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(@"AVPlayer Failed");
} else if (player.status == AVPlayerStatusReadyToPlay) {
NSLog(@"AVPlayer Ready to Play");
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(@"AVPlayer Unknown");
}
}
}
I got this message when App crashed.
当应用程序崩溃时,我收到了这条消息。
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x165297c0 of class AVPlayer was deallocated while key value observers were still registered with it. Current observation info: ( Context: 0x0, Property: 0x1661d5d0> )'
*** 由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“类 AVPlayer 的实例 0x165297c0 已被释放,而键值观察者仍在其中注册。当前观察信息:(上下文:0x0,属性:0x1661d5d0>)'
Application crashed only in IOS 8 in IOS 7 works fine.What I am doing wrong??
仅在 IOS 8 中崩溃的应用程序在 IOS 7 中工作正常。我做错了什么??
回答by Ralph
I had a similar problem. It worked fine in iOS 7, and now it crashes in iOS 8.
我有一个类似的问题。它在 iOS 7 中运行良好,现在它在 iOS 8 中崩溃了。
The solution was to remove the observer, before releasing the object.
解决方案是在释放对象之前移除观察者。
When you replace or allocate a new object for a member, you're releasing the old object, so you need to remove the observer first :
当您为成员替换或分配新对象时,您正在释放旧对象,因此您需要先删除观察者:
-(void) setupAVPlayerForURL: (NSURL*) url1 {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url1 options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
if (player != nil)
[player removeObserver:self forKeyPath:@"status"];
player = [AVPlayer playerWithPlayerItem:anItem];
[player addObserver:self forKeyPath:@"status" options:0 context:nil];
}
And similarly in btnPlayClick ( in case it is pressed without btnStop_Click being pressed) :
同样在 btnPlayClick 中(以防在没有按下 btnStop_Click 的情况下按下它):
- (IBAction)btnPlay_Click:(id)sender {
if (player != nil && [player currentItem] != nil)
[[player currentItem] removeObserver:self forKeyPath:@"timedMetadata"];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
[player play];
}
回答by Mohit Singh
-(void)viewWillDisappear:(BOOL)animated
{
[self.player removeObserver:self forKeyPath:@"status" context:nil];
}
回答by mmccomb
When using KVO you must balance calls to addObserver:forKeyPath:options:context:
with calls to removeObserver:forKeyPath:
(see the KVO programming guide).
使用 KVO 时,您必须平衡调用 toaddObserver:forKeyPath:options:context:
和调用 to removeObserver:forKeyPath:
(请参阅KVO 编程指南)。
Try removing the view controller as an observer when the stop button is tapped e.g.
当点击停止按钮时,尝试将视图控制器作为观察者移除,例如
- (IBAction)btnStop_Click:(id)sender {
[[player currentItem] removeObserver:self forKeyPath:@"timedMetadata"];
}
回答by ShannonChenCHN
I did meet the similar issue when using AVPlayer, the crash log info says:
我在使用 AVPlayer 时确实遇到了类似的问题,崩溃日志信息说:
An instance 0x174034600 of class AVKeyPathFlattener was deallocated while key value observers were still registered with it. Current observation info: ( Context: 0x0, Property: 0x17405d6d0> )
AVKeyPathFlattener 类的实例 0x174034600 已被释放,而键值观察者仍在向其注册。当前观察信息:(上下文:0x0,属性:0x17405d6d0>)
As what Apple recommended, what I originally did is adding observer after initialize my AVPlayerItem object, and remove observer in the observer's dealloc method. Because my observer class kept a strong reference on my AVPlayerItem object, so it should not be deallocated before my observer object was deallocated. I really don't know why this happens.
正如苹果推荐的那样,我最初做的是在初始化我的 AVPlayerItem 对象后添加观察者,并在观察者的 dealloc 方法中删除观察者。因为我的观察者类在我的 AVPlayerItem 对象上保持了一个强引用,所以在我的观察者对象被释放之前它不应该被释放。我真的不知道为什么会发生这种情况。
So I tried solved this problem by using BlocksKit
, it works fine for me right now.
所以我尝试通过使用来解决这个问题BlocksKit
,它现在对我来说很好用。
回答by neowinston
It's wise to verify first if the key is being observed or not before removing the observer with a @try @catch
, like so:
在使用 a 删除观察者之前,首先验证是否正在观察密钥是明智的@try @catch
,如下所示:
@try {
[self.player removeObserver:self forKeyPath:@"status" context:nil];
} @catch (id anException) {
//do nothing, obviously it wasn't attached because an exception was thrown
NSLog(@"status key not being observed");
}