Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

respondsToSelector but the selector is unrecognized

Tags:

ios

selector

I'm following apple's example code to the letter for how to implement receipt validation under iOS 7, and it works, except when I run the following code (taken basically verbatim from their sample) under iOS 6

NSBundle *bundle =[NSBundle mainBundle];
if ([bundle respondsToSelector:@selector(appStoreReceiptURL)]) { // can do local device receipt validation
    NSURL *receiptURL = [bundle performSelector:@selector(appStoreReceiptURL)];
}

It returns true to the responds to selector, and therefore tries to perform the selector at which point it crashes because the selector doesn't exist... Why am I getting a positive response to a selector that doesn't exist?

like image 392
ima747 Avatar asked Sep 16 '13 21:09

ima747


3 Answers

The documentation for appStoreReceiptURL explains that this method existed as a private method before iOS 7, and that its implementation prior to iOS 7 calls doesNotRecognizeSelector:. Therefore you cannot use respondsToSelector: to check whether it's ok to call the method.

Instead, you need to check the system version:

NSString *version = [UIDevice currentDevice].systemVersion;
if ([version compare:@"7.0" options:NSNumericSearch] != NSOrderedAscending) {
    // safe to use appStoreReceiptURL
} else {
    // not safe to use appStoreReceiptURL
}
like image 173
rob mayoff Avatar answered Oct 31 '22 08:10

rob mayoff


I also got bitten by the bad sample code given at the WWDC session. It looks like Apple has updated their documentation with new reccomended sample code:

if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_6_1) {
   // Load resources for iOS 6.1 or earlier
} else {
   // Load resources for iOS 7 or later
}

Based on this sample, you could write it in a single branch like so if you prefer, and check afterwards if the object is nil:

NSURL* url = nil;
if (floor(NSFoundationVersionNumber) > NSFoundationVersionNumber_iOS_6_1) {
    //iOS 7 or later, safe to use appStoreReceiptURL
    url = [[NSBundle mainBundle] performSelector:@selector(appStoreReceiptURL)];
}
like image 30
Eliot Avatar answered Oct 31 '22 09:10

Eliot


I saw that in the WWDC 2013 talk (e.g., “Using Receipts to Protect Your Digital Sales”) too. And the conflicting statement in the appStoreReceiptURL docs. It seems that the WWDC 2013 code example for appStoreReceiptURL was untested.

like image 24
Chris Prince Avatar answered Oct 31 '22 07:10

Chris Prince