如何释放MPMoviePlayerController?

26

我有几个视图需要访问电影播放器。我在AppDelegate中为这些视图编写了以下代码。它们会发送要播放的文件名。代码工作正常但我知道需要释放某些内容。如果我将最后一行添加为 release 或 autorelease,当用户按下 movieplayer 上的 done 按钮时,应用程序将崩溃。

MPMoviePlayerController *moviePlayer = [[MPMoviePlayerController alloc] 
                 initWithContentURL:[NSURL fileURLWithPath:moviePath]];
moviePlayer.movieControlMode = MPMovieControlModeDefault;
[moviePlayer play];
//[moviePlayer release];

我遇到了这个错误:

objc[51051]: FREED(id): message videoViewController sent to freed object=0x1069b30

程序接收到信号:“EXC_BAD_INSTRUCTION”。

我应该如何释放播放器?

6个回答

18
我发现的是,在安全释放 MPMoviePlayerController 之前,必须向其发送停止消息。因此,在 handlePlaybackEnd 中,我首先停止它,然后自动释放它。调用 release 看起来效果不太好:
- (void) moviePlayBackDidFinish : (NSNotification *) notification
{
  VideoPlayerController * player = notification.object;
  [player stop];
  [player autorelease];
}

整个过程变得有些棘手,因为MPMoviePlayerPlaybackDidFinishNotification可能会被发送多次,但是调用stop/autorlease两次也没有任何好处。所以你需要设法防范这种情况。
最后,似乎需要进行几次主运行循环的迭代才能安全地创建一个新的MPMoviePlayerController实例。如果你做得太快,你会听到声音但看不到视频。非常有趣,对吧?

是的-我已经解决了声音/无视频的问题。太棒了!你如何防止多个通知?如果处理多个通知,会崩溃吗? - 4thSpace
你需要有某种标志:如果它没有设置,就设置它并释放玩家。如果它已经设置了,就不要做任何事情。 - unwesen
4
你可以将MPMoviePlayerController作为委托中的ivar进行存储。在moviePlaybackDidFinish:方法中,你可以释放ivar并将其设置为nil,而不是访问notification.object。第二个通知将向nil发送stop和autorelease,这是可以的。 - Daniel Dickison
有时候,即使用户点击了“完成”按钮,我仍然会在后台听视频中的音频。对ivar播放器进行自动释放(而不是释放)对我很有帮助。 - leolobato

7

回答4thSpace在上面的答案中的评论,你可以删除通知观察器,这样你就不会收到多次通知:

- (void)moviePlayBackDidFinish:(NSNotification *)notification {
    MPMoviePlayerController *theMovie = [notification object];
    [[NSNotificationCenter defaultCenter] removeObserver:self
        name:MPMoviePlayerPlaybackDidFinishNotification
        object:theMovie];
    [theMovie stop];
    [theMovie release];
}

我已经尝试过这个,但我的内存消耗没有降下来?这是否意味着内存还没有被释放? - Nnp

3

针对iPhone OS 3.2版本,您需要在调用[moviePlayer stop];之前调用[moviePlayer pause];


2

如果播放器没有到达结尾,仅停止和释放是不够的。

我的解决方案是在释放之前,在 moviePlayBackDidFinish: 中设置 moviePlayer.initialPlaybackTime = -1

-(void)playMovie: (NSString *)urlString{ 
    movieURL = [NSURL URLWithString:urlString]; 
    moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:movieURL]; 
    moviePlayer.initialPlaybackTime = 0; 
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(moviePlayBackDidFinish: ) name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer] ;

    moviePlayer.scalingMode = MPMovieScalingModeAspectFit; 
    moviePlayer.movieControlMode = MPMovieControlModeDefault;
    moviePlayer.backgroundColor = [UIColor blackColor];

    [moviePlayer play];
}

-(void)moviePlayBackDidFinish: (NSNotification*)notification{ 
    [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:moviePlayer] ; 

    moviePlayer.initialPlaybackTime = -1; 

    [moviePlayer stop]; 
    [moviePlayer release]; 
}

0

我曾经遇到过同样的问题,后来才发现我设置了通知方法时使用了 object:nil(这是复制粘贴的结果)。

尽管我本不应该收到任何通知,但我却收到了多个通知。

以下是我新的通知设置代码,已经解决了所有问题(请注意 object:moviePlayer):

[[NSNotificationCenter defaultCenter] addObserver:self 
                           selector:@selector(moviePlaybackDidFinish:) 
                           name:MPMoviePlayerPlaybackDidFinishNotification 
                           object:moviePlayer]; 

希望这有所帮助。现在我的所有代码都正常工作了。

0

这似乎显著减少了内存。然而,在IOS 4.1上看起来还好。

- (void)videoFinishedCallback:(NSNotification *)aNotification
{
    thePlayer = [aNotification object];
    [[NSNotificationCenter defaultCenter]
    removeObserver:self
    name:MPMoviePlayerPlaybackDidFinishNotification object:thePlayer];

    thePlayer.initialPlaybackTime = -1;

    #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 30200
        [thePlayer pause]; 
    #endif

    [thePlayer stop];
    [thePlayer release];    
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接