我创建了一个带有游戏商店视图和视图控制器的游戏。 可以通过菜单(ViewController.m)和Game Over屏幕(GameViewController.m)访问商店。
我的问题是,如果我在菜单中显示了一次商店,然后玩游戏并通过屏幕访问游戏中的商店并尝试购买东西,那么应用程序会在没有太多信息的情况下崩溃EXC_BAD_ACCESS错误。 (打破
[[SKPaymentQueue defaultQueue] addPayment:lPayment];
尝试购买IAP时,在我的ShopViewController中的ButtonPressed操作中行。
我的观点设置如下:
菜单视图 - > Ladderview - > Gameview - > ShopView
和
菜单视图 - > Shopview
希望你能帮助我查明错误,
编辑-----------
似乎我可以从菜单中重现错误 - > Shopview不使用游戏视图。我可以通过按“购买按钮”,按取消,导航回菜单,返回商店,然后重复来完成此操作。在第3-4次尝试时,它在同一行崩溃。这是按下整个按钮的方法:
- (void)buyButtonPressed:(UIButton *)pButton {
NSInteger lTag = [pButton tag];
//////NSLog(@"Button tag: %i"), lTag;
Reachability *lReachability = [Reachability reachabilityForInternetConnection];
NetworkStatus lCurrentNetworkStatus = [lReachability currentReachabilityStatus];
if (lCurrentNetworkStatus != NotReachable) {
if ([SKPaymentQueue canMakePayments]) {
SKPayment *lPayment = [SKPayment paymentWithProduct:[mPriceArray objectAtIndex:lTag]];
[[SKPaymentQueue defaultQueue] addPayment:lPayment];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
} else {
[self showAlertViewWithText:@"Purchases are disabled. Please check your settings for General -> Restrictions -> In-App Purchases and try again." andTitle:@"Warning"];
}
} else {
[self showAlertViewWithText:@"No network connection!" andTitle:@"Warning"];
}
}
所以看起来lPayment正在被取消分配。我甚至试图设置
mProductIds = nil;
mPriceArray = nil;
当我删除商店视图时,试图强制它在我重新加载商店时再次分配它,但没有任何运气。
由于
答案 0 :(得分:3)
你的问题是一个悬垂的指针。 EXC_BAD_ACCESS是CPU呻吟,您正在处理访问权限区域之外的不存在的内存或内存。原因是缺乏对象的保留,导致早期释放,然后被覆盖。在那个时候(可能被延迟),指针将指向垃圾,其解除引用(类检查)导致抛出EXC_BAD_ACCESS。使用@try无法捕获此错误。这里有一个假设,堆栈本身是腐败的,导致继续是不可能的(尽管很可能不是这种情况),这会抛出调试器进行旋转,其当前的状态输出在许多领域已经缺乏。当CPU重置重要寄存器并执行长跳转时,这就像无法控制的无政府状态。
考虑自动引用计数。在您已经存在的情况下,请考虑主机对象不保留类似委托的属性。任何逻辑上可以包含self的属性都不会保留存储在其中的任何值。 ARC不会帮助你。
在你的情况下:defaultQueue可能是好的。 lPayment可能已被解除分配。
答案 1 :(得分:1)
首先尝试在启用NSZombie时跟踪问题。在EXC_BAD_Access的情况下问题一段时间(NSZombie)跟踪解除分配的对象变得比简单猜测问题所在的地方更有用。
答案 2 :(得分:1)
很难从提供的信息中得知,但可能如下:您的陈述
SKPayment *lPayment = [SKPayment paymentWithProduct:[mPriceArray objectAtIndex:lTag]];
实例化SKPayment对象,并将其交给当前的自动释放池。如果此池不存在(如果代码在没有显式设置自动释放池的单独线程中运行,则可能就是这种情况),该对象将立即再次释放,并且您的语句
[[SKPaymentQueue defaultQueue] addPayment:lPayment];
访问无效内存。