开发者

iPhone OS 3.2 - How to register for notifcations that may not be available

So I'm trying to register for the 开发者_StackOverflow社区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?


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.


This also works:

if (&MPMoviePlayerDidExitFullscreenNotification) {

}

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


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜