views:

466

answers:

4

So I'm trying to register for the MPMoviePlayerDidExitFullscreenNotification notification in my universal app (iPhone and iPad).

Problem is, OS 3.1.3 doesn't support this notification, and just crashes.

I've tried version checking, like so:

if ([MPMoviePlayerController instancesRespondToSelector:@selector(setShouldAutoplay:)])
{//Check for shouldSetAutoplay, this ensures that we are running at least 3.2
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinish:) name:(NSString*)class2 object:[self player]];

Doesn't work, still crashes. How do I do this?

+2  A: 

Since MPMoviePlayerDidExitFullscreenNotification is a symbol, it must be known at (dynamic) link time for any versions. Run time check doesn't help.

To solve this, you need to delay loading of this to run time. You could use dlsym:

NSString* x_MPMoviePlayerDidExitFullscreenNotification
  = dlsym(RTLD_DEFAULT, "MPMoviePlayerDidExitFullscreenNotification");
if (x_MPMoviePlayerDidExitFullscreenNotification != nil) {
  [[NSNotificationCenter defaultCenter] addObserver:self ...];
}

Alternatively, you may make MPMoviePlayerDidExitFullscreenNotification a weak symbol so when dyld doesn't find that symbol, instead of crashing it will just set it to NULL.

Finally, since MPMoviePlayerDidExitFullscreenNotification is just a constant string, you could simply use

… name:@"MPMoviePlayerDidExitFullscreenNotification" …

But the content of that string is implementation detail. There's no guarantee (although rare) that Apple won't change it to something else in the later versions.

KennyTM
Yeah, that's exactly what's happening.I just used the string instead of the constant. Hope nothing changes... ;-)Thanks!
cdstamper
+1  A: 

To answer your actual question:

You should be able to register for any notification without crashing. As Kenny says, it's a symbol, so the correct registration for 3.2 is;

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinish:) name:MPMoviePlayerDidExitFullscreenNotification object:[self player]];

For code that works in 3.13, you can assume that the symbol is just a convenience for the compiler, and use a string instead:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerDidFinish:) name:@"MPMoviePlayerDidExitFullscreenNotification" object:[self player]];

You test using shouldAutoplay is fine, although I'd prefer to all it directly on the instance I would be using - ie [self player]. It's probably that your real problem is using class2 cast to NSString as the notification name.

Paul Lynch
Thanks, using the @"MPMoviePlayerDidExitFullscreenNotification" rather than the const works great!
cdstamper
+2  A: 

This also works:

if (&MPMoviePlayerDidExitFullscreenNotification) {

}

Note you have to check the address of the symbol otherwise you will get a crash.

Mike Weller
A: 

I needed exactly this but I did prefer using dlsym as KennyTM suggested, however, I needed to do a small change for it to work so I guess that was a bug (please correct me if I'm wrong). This is the code snippet I'm using which works great:

NSString* x_MPMoviePlayerDidExitFullscreenNotification = *(NSString**)dlsym(RTLD_DEFAULT, "MPMoviePlayerDidExitFullscreenNotification");
        if (x_MPMoviePlayerDidExitFullscreenNotification != nil) {
            [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didExitFullscreen:) name:x_MPMoviePlayerDidExitFullscreenNotification object: self.videoPlayer];
        }

The change from KennyTM's snippet was the *(NSString**) cast after dlsym as it seems dlsym will return a pointer to the symbol.

jberg.fi