Ios 疯狂崩溃EXC_坏访问内核地址无效,iPhone应用内购买
无法通过iPhone上的应用程序内购买修复奇怪的崩溃Ios 疯狂崩溃EXC_坏访问内核地址无效,iPhone应用内购买,ios,crash,in-app-purchase,crash-reports,storekit,Ios,Crash,In App Purchase,Crash Reports,Storekit,无法通过iPhone上的应用程序内购买修复奇怪的崩溃EXC\u BAD\u ACCESS KERN\u INVALID\u ADDRESS。它以不同的体系结构出现在我的所有应用程序上。它不依赖于iOS版本或设备。是什么导致了这个问题 在应用程序上处理应用程序内购买的完整代码: #pragma mark In-App Purchase - (NSString*)getProductId:(NSString*)feature { NSBundle *bundle = [NSBundle
EXC\u BAD\u ACCESS KERN\u INVALID\u ADDRESS
。它以不同的体系结构出现在我的所有应用程序上。它不依赖于iOS版本或设备。是什么导致了这个问题
在应用程序上处理应用程序内购买的完整代码:
#pragma mark In-App Purchase
- (NSString*)getProductId:(NSString*)feature {
NSBundle *bundle = [NSBundle mainBundle];
NSDictionary *info = [bundle infoDictionary];
NSString *bundleIdentifier = [info objectForKey: @"CFBundleIdentifier"];
return [NSString stringWithFormat:feature, [bundleIdentifier stringByReplacingOccurrencesOfString:@"-" withString:@""]];
}
- (void)requestItems:(NSString*)feature {
NSSet *productIdentifiers = [NSSet setWithObject:[self getProductId:feature]];
if ([feature isEqualToString:g100Items]) {
if (product100ItemsRequest) {
[product100ItemsRequest release];
product100ItemsRequest = nil;
}
product100ItemsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
product100ItemsRequest.delegate = self;
[product100ItemsRequest start];
// we will release the request object in the delegate callback
} else
if ([feature isEqualToString:gUnlimitedItems]) {
if (productUnlimitedItemsRequest) {
[productUnlimitedItemsRequest release];
productUnlimitedItemsRequest = nil;
}
productUnlimitedItemsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productUnlimitedItemsRequest.delegate = self;
[productUnlimitedItemsRequest 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:g100Items]]) {
[button100Items setTitle:[NSString stringWithFormat:g100ItemsButton, product.localizedPrice] forState:UIControlStateNormal];
// finally release the reqest we alloc/init’ed in requestItems
[product100ItemsRequest release];
product100ItemsRequest = nil;
}
if (product && [product.productIdentifier isEqualToString:[self getProductId:gUnlimitedItems]]) {
[buttonUnlimitedItems setTitle:[NSString stringWithFormat:gUnlimitedItemsButton, product.localizedPrice] forState:UIControlStateNormal];
// finally release the reqest we alloc/init’ed in requestItems
[productUnlimitedItemsRequest release];
productUnlimitedItemsRequest = 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:(BOOL)tryAgain {
if (tryAgain) {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
NSMutableArray *oldProducts = products;
products = [[[NSMutableArray alloc] initWithObjects: nil] retain];
[oldProducts release];
}
// 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 requestItems:g100Items];
[self requestItems:gUnlimitedItems];
}
// call this before making a purchase
- (BOOL)canMakePurchases {
return [SKPaymentQueue canMakePayments];
}
// kick off the upgrade transaction
- (void)purchaseItems:(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];
// Calling AppStore Dialog
}
ok = true;
break;
}
}
if (!ok) {
[self loadStore:YES];
[self showAlert:gInAppAlertTitle alertStr:gNoProductsToMakePurchase];
return;
}
}
// saves a record of the transaction by storing the receipt to disk
- (void)recordTransaction:(SKPaymentTransaction *)transaction {
if ([transaction.payment.productIdentifier isEqualToString:[self getProductId:g100Items]]) {
// save the transaction receipt to disk
[[NSUserDefaults standardUserDefaults] setValue:[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]/*transaction.transactionReceipt*/ forKey:[self getProductId:g100Items]];
[[NSUserDefaults standardUserDefaults] synchronize];
} else
if ([transaction.payment.productIdentifier isEqualToString:[self getProductId:gUnlimitedItems]]) {
// save the transaction receipt to disk
[[NSUserDefaults standardUserDefaults] setValue:[NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]]/*transaction.transactionReceipt*/ forKey:[self getProductId:gUnlimitedItems]];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
// enable pro features
- (bool)provideContent:(NSString *)productId {
if (productId) {
FirstViewController* firstViewController = [[tabBarController viewControllers] objectAtIndex:gSourceTabIndex];
if ([productId isEqualToString:[self getProductId:g100Items]]) {
firstViewController.itemCount += 100;
[firstViewController saveItems];
// 100 Items Provided
return true;
} else
if ([productId isEqualToString:[self getProductId:gUnlimitedItems]]) {
firstViewController.itemCount = gItemUnlimitedCount;
[firstViewController saveItems];
// Unlimited Items Provided
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 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:gInAppAlertTitle 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)process100Items:(id)sender {
if ([self canMakePurchases]) {
[self purchaseItems:g100Items];
} else {
[self showAlert:gInAppAlertTitle alertStr:gCanNotMakePurchases];
}
// Buy 100 Items Button Pressed
}
- (IBAction)processUnlimitedItems:(id)sender {
if ([self canMakePurchases]) {
[self purchaseItems:gUnlimitedItems];
} else {
[self showAlert:gInAppAlertTitle alertStr:gCanNotMakePurchases];
}
// Buy Unlimited Items Button Pressed
}
- (IBAction)restoreCompletedTransactions:(id)sender {
if ([products count] == 0) {
[self loadStore:YES];
[self showAlert:gInAppAlertTitle alertStr:gNoProductsToMakePurchase];
return;
}
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
还有一个崩溃日志,例如:
该项目不使用ARC。我无法在我的设备上重现该问题
更新
在代理属性中的第一个应用程序self
上,作为.xib表单上的UITabViewController
的一部分,是@interface FourthViewController:UIViewController
。当用户选择选项卡时,它将加载到内存中。我从来没有看到它从记忆中被卸下
在第二个应用程序上,委托属性中的self
是@接口设置视图:UIViewController
。它通过类@interface RootViewController:UIViewController
的代码加载到内存中:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
me = self;
settingsView = [[SettingsView alloc] initWithNibName:nil bundle:nil];
}
}
- (void)dealloc {
[settingsView release];
[super dealloc];
}
父类正在通过以下代码加载到内存中:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
self.window = [[[UIWindow alloc] initWithFrame:getDeviceBounds] autorelease];
RootViewController *rc = [[RootViewController alloc] initWithNibName:nil bundle:nil];
[self.window setRootViewController:rc];
root = rc;
[self.window makeKeyAndVisible];
}
我找到了代码:
- (void)restartApp {
RootViewController *toRemove = root;
RootViewController *rc = [[RootViewController alloc] initWithNibName:nil bundle:nil];
[self.window setRootViewController:rc];
root = rc;
[toRemove release];
}
因此,我可以修复第二个应用程序上的错误。但是我不确定第一个应用程序的情况。最可能发生的情况是您的委托已经被解除分配。
SKProductsRequest
的委托定义为
@property(nonatomic, assign) id<SKProductsRequestDelegate> delegate;
@属性(非原子,赋值)id委托;
由于它是assign
,这意味着它既不会保留代理,也不会在释放代理时保持nil
您没有指明此代码来自哪个类,但我可以看到代理是self
我建议您设置一个断点,或者在类“dealloc
中添加一个NSLog
。通过这种方式,您可以了解情况是否确实如此(代理正在被解除分配),然后确定是谁在释放它
人们常犯的一个错误是将委托设置为UIKit对象,如UIView或UIViewController。当屏幕更改时,该对象被解除锁定,请求完成时的委托现在不再有效。最可能发生的情况是您的委托已解除锁定。
SKProductsRequest
的委托定义为
@property(nonatomic, assign) id<SKProductsRequestDelegate> delegate;
@属性(非原子,赋值)id委托;
由于它是assign
,这意味着它既不会保留代理,也不会在释放代理时保持nil
您没有指明此代码来自哪个类,但我可以看到代理是self
我建议您设置一个断点,或者在类“dealloc
中添加一个NSLog
。通过这种方式,您可以了解情况是否确实如此(代理正在被解除分配),然后确定是谁在释放它
人们常犯的一个错误是将委托设置为UIKit对象,如UIView或UIViewController。当屏幕更改时,该对象被解除锁定,请求完成时的委托现在不再有效。将
委托声明为弱是否可以解决此问题?是的,这将是解决此问题的理想方法。我的缺点是没有明确提到它。将委托
声明为弱
不会解决这个问题吗?是的,这将是解决这个问题的理想方法。我很抱歉没有明确提及此事。