How to release MPMoviePlayerController?

2019-01-22 02:19发布

问题:

I have a couple of views that access the movie player. I've put the following code in a method in AppDelegate for these views. They send in the filename to play. The code works fine but I know a release is required somewhere. If I add the last line as a release or autorelease, the app will crash once the user presses done on the movieplayer.

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

I get this error:

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

Program received signal: “EXC_BAD_INSTRUCTION”.

How should I be releasing the player?

回答1:

What I've found is that the MPMoviePlayerController has to be sent the stop message before you can safely release it. So I do it in handlePlaybackEnd - first I stop it, then I autorelease it. Calling release doesn't seem to work too well:

- (void) moviePlayBackDidFinish : (NSNotification *) notification
{
  VideoPlayerController * player = notification.object;
  [player stop];
  [player autorelease];
}

The whole thing becomes a bit trickier in that the MPMoviePlayerPlaybackDidFinishNotification can get sent more than once, but calling stop/autorlease twice won't do you any good either. So you need to guard against that somehow.

Lastly, it seems to take a few iterations of the main run loop until you can safely create a new MPMoviePlayerController instance. If you do it too quickly, you'll get sound but no video. Great fun, huh?



回答2:

To answer 4thSpace's comment on the answer above, you can remove the notification observer so you don't receive it multiple times:

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


回答3:

for iphone os 3.2 you need to call [moviePlayer pause]; before calling [moviePlayer stop];



回答4:

Stopping and releasing was not enough for me if the player did not reach to its end.

My solution is setting the moviePlayer.initialPlaybackTime = -1 at the moviePlayBackDidFinish: before releasing it:

-(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]; 
}


回答5:

I had the same problem and I just realized I set the notification method with object:nil (it was a copy paste).

I was having multiple notifications although I shouldn't have had any notifications at all.

Here is my new notification set up code that fixed all (see the object:moviePlayer):

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

Hope that helps. Now all my code is working properly.



回答6:

This seemed to reduce the memory significantly. However for IOS 4.1 it seems fine.

- (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];    
}