我有以下代码将应用程序内购买添加到应用程序中.一切都在我的设备上完美运行.但是,当我添加Crashlytics
对应用程序的支持时,我每天都会收到数百份崩溃报告.为什么?我真的无法理解提供的代码有什么问题.
#define kInAppPurchaseManagerProductsFetchedNotification @"kInAppPurchaseManagerProductsFetchedNotification" #define kInAppPurchaseManagerTransactionFailedNotification @"kInAppPurchaseManagerTransactionFailedNotification" #define kInAppPurchaseManagerTransactionSucceededNotification @"kInAppPurchaseManagerTransactionSucceededNotification" #define gFullVersion @"%@.FullVersion" - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { [self loadStore]; } } - (NSString*)getProductId:(NSString*)feature { NSBundle *bundle = [NSBundle mainBundle]; NSDictionary *info = [bundle infoDictionary]; NSString *bundleIdentifier = [info objectForKey: @"CFBundleIdentifier"]; return bundleIdentifier; } - (void)requestProducts:(NSString*)feature { NSSet *productIdentifiers = [NSSet setWithObject:[self getProductId:feature]]; if ([feature isEqualToString:gFullVersion]) { if (productFullVersionRequest) { [productFullVersionRequest release]; productFullVersionRequest = nil; } productFullVersionRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; productFullVersionRequest.delegate = self; [productFullVersionRequest start]; // we will release the request object in the delegate callback } } - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response { [products addObjectsFromArray:response.products]; for (SKProduct *product in response.products) { if (product && [product.productIdentifier isEqualToString:[self getProductId:gFullVersion]]) { // finally release the reqest we alloc/init’ed in requestCompilations [productFullVersionRequest release]; productFullVersionRequest = nil; } } for (NSString *invalidProductId in response.invalidProductIdentifiers) { NSLog(@"Invalid product id: %@" , invalidProductId); } [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil]; } // call this method once on startup - (void)loadStore { // restarts any purchases if they were interrupted last time the app was open [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; // get the product description (defined in early sections) [self requestProducts:gFullVersion]; } // call this before making a purchase - (BOOL)canMakePurchases { return [SKPaymentQueue canMakePayments]; } // kick off the upgrade transaction - (void)purchaseProduct:(NSString*)feature { bool ok = false; for (SKProduct *product in products) { if ([product.productIdentifier isEqualToString:[self getProductId:feature]]) { SKPayment *payment = [SKPayment paymentWithProduct:product]; if (payment) { [[SKPaymentQueue defaultQueue] addPayment:payment]; break; } } } } // saves a record of the transaction by storing the receipt to disk - (void)recordTransaction:(SKPaymentTransaction *)transaction { if ([transaction.payment.productIdentifier isEqualToString:[self getProductId:gFullVersion]]) { // save the transaction receipt to disk [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:[self getProductId:gFullVersion]]; [[NSUserDefaults standardUserDefaults] synchronize]; } } // enable pro features - (bool)provideContent:(NSString *)productId { if ([productId isEqualToString:[self getProductId:gFullVersion]]) { // ...provide content here... return true; } return false; } // removes the transaction from the queue and posts a notification with the transaction result - (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful { // remove the transaction from the payment queue. [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil]; if (wasSuccessful) { // send out a notification that we’ve finished the transaction [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo]; } else { // send out a notification for the failed transaction [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo]; } } // called when the transaction was successful - (void)completeTransaction:(SKPaymentTransaction *)transaction { [self recordTransaction:transaction]; bool provided = [self provideContent:transaction.payment.productIdentifier]; [self finishTransaction:transaction wasSuccessful:YES]; } // called when a transaction has been restored and and successfully completed - (void)restoreTransaction:(SKPaymentTransaction *)transaction { [self recordTransaction:transaction.originalTransaction]; [self provideContent:transaction.originalTransaction.payment.productIdentifier]; [self finishTransaction:transaction wasSuccessful:YES]; } // called when a transaction has failed - (void)failedTransaction:(SKPaymentTransaction *)transaction { if (transaction.error.code != SKErrorPaymentCancelled) { // error! [self finishTransaction:transaction wasSuccessful:NO]; [self showAlert:NSLocalizedString(@"InAppPurchase", @"") alertStr:[transaction.error localizedDescription]]; } else { // this is fine, the user just cancelled, so don’t notify [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } } // called when the transaction status is updated - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { switch (transaction.transactionState) { case SKPaymentTransactionStatePurchased: [self completeTransaction:transaction]; break; case SKPaymentTransactionStateFailed: [self failedTransaction:transaction]; break; case SKPaymentTransactionStateRestored: [self restoreTransaction:transaction]; break; default: break; } } } - (IBAction)processFullVersion:(id)sender { if ([self canMakePurchases]) { [self purchaseProduct:gFullVersion]; } else { [self showAlert:NSLocalizedString(@"InAppPurchase", @"") alertStr:NSLocalizedString(@"CanNotMakePurchases", @"")]; } } - (IBAction)restoreCompletedTransactions:(id)sender { [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; }
崩溃报告:
Crashed: com.apple.main-thread EXC_BAD_ACCESS KERN_INVALID_ADDRESS at 0xa1c57ae2 Thread : Crashed: com.apple.main-thread 0 libobjc.A.dylib 0x3bf5e5d0 objc_msgSend + 15 1 StoreKit 0x360260a7 __NotifyObserverAboutChanges + 66 2 CoreFoundation 0x341aeacd CFArrayApplyFunction + 176 3 StoreKit 0x36026055 -[SKPaymentQueue _notifyObserversAboutChanges:sendUpdatedDownloads:] + 128 4 StoreKit 0x36024bc9 -[SKPaymentQueue addPayment:] + 464 5 MyApplication 0x000a76d7 -[CalendarView purchaseProduct:] (CalendarView.m:952) 6 MyApplication 0x000a8c17 -[CalendarView processFullVersion:] (CalendarView.m:1107) 7 MyApplication 0x000a361b -[CalendarView clickHandler:] (CalendarView.m:458) 8 MyApplication 0x000a55cf -[CalendarView liteVersionDisplayAlert] (CalendarView.m:671) 9 MyApplication 0x000a5d2f -[CalendarView toggleView:] (CalendarView.m:735) 10 MyApplication 0x000a625f -[CalendarView modeButtonPressed] (CalendarView.m:795) 11 MyApplication 0x000c245f -[ToolbarView modePressed] (ToolbarView.m:304) 12 UIKit 0x36162087 -[UIApplication sendAction:to:from:forEvent:] + 70 13 UIKit 0x3616203b -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 30 14 UIKit 0x36162015 -[UIControl sendAction:to:forEvent:] + 44 15 UIKit 0x361618cb -[UIControl(Internal) _sendActionsForEvents:withEvent:] + 502 16 UIKit 0x36161db9 -[UIControl touchesEnded:withEvent:] + 488 17 UIKit 0x3608a5f9 -[UIWindow _sendTouchesForEvent:] + 524 18 UIKit 0x360778e1 -[UIApplication sendEvent:] + 380 19 UIKit 0x360771ef _UIApplicationHandleEvent + 6198 20 GraphicsServices 0x37d8f5f7 _PurpleEventCallback + 590 21 GraphicsServices 0x37d8f227 PurpleEventCallback + 34 22 CoreFoundation 0x3423d3e7 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 34 23 CoreFoundation 0x3423d38b __CFRunLoopDoSource1 + 138 24 CoreFoundation 0x3423c20f __CFRunLoopRun + 1382 25 CoreFoundation 0x341af23d CFRunLoopRunSpecific + 356 26 CoreFoundation 0x341af0c9 CFRunLoopRunInMode + 104 27 GraphicsServices 0x37d8e33b GSEventRunModal + 74 28 UIKit 0x360cb2b9 UIApplicationMain + 1120 29 MyApplication 0x0007daff main (main.m:13)
非常感谢您的帮助!
您添加到付款队列中的观察者似乎已被取消分配.你打电话SKPaymentQueue addTransactionObserver:
但你从不打电话SKPaymentQueue removeTransactionObserver:
.
dealloc
向视图控制器添加方法:
- (void)dealloc { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; }
很可能你的应用程序显示了一个视图控制器,它将自己添加为观察者.然后该视图控制器被解除(但仍标记为观察者).稍后您将显示控制器的另一个实例并执行一些支付交易.然后,支付队列尝试通知新老观察者.崩溃的发生是因为旧的观察者早已被解除分配.
通过添加上述dealloc
方法,将解决此问题.