【问题标题】:In App Purchase/View Controller Crash: Message sent to deallocated instance在 App Purchase/View Controller Crash: Message sent to deallocated instance
【发布时间】:2012-08-11 17:10:12
【问题描述】:

我的视图控制器上有一个按钮,用于显示我的应用内购买商店。

storeSinglePlayer *ssp = [[storeSinglePlayer alloc] initWithNibName:@"storeSinglePlayer" bundle:nil];

//Animation Code

CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush; 
transition.subtype = kCATransitionFromTop;
[self.navigationController.view.layer addAnimation:transition forKey:nil];

[self.navigationController pushViewController:ssp animated:NO];

导航控制器成功将这个商店推送到屏幕上。商店有一个执行以下代码的后退按钮:

[self.request cancel];
self.request.delegate = nil;
self.request = nil;
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

CATransition* transition = [CATransition animation];
transition.duration = 0.5;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.type = kCATransitionPush;
transition.subtype = kCATransitionFromBottom; 
[self.navigationController.view.layer addAnimation:transition forKey:nil];


[self.navigationController popViewControllerAnimated:NO];

这也成功执行。但是,如果我现在再次单击按钮以显示商店视图控制器,我会收到以下消息:

-[storeSinglePlayer respondsToSelector:]: message sent to deallocated instance 0xd642df0

这确实是一个非常著名的问题。正如您将在上面的代码中注意到的那样,我已经合并了我在 stackoverflow 上遇到的各种帖子的建议。已实现以下代码:

[self.request cancel];
self.request.delegate = nil;
self.request = nil;
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

我的属性和相应的合成设置为:

@property (nonatomic, strong) SKProductsRequest *request;
@synthesize request = _request;

我不知道,为什么会崩溃!

P.S:该项目已启用 ARC。

【问题讨论】:

  • 确保你没有发布它两次..?还是你在使用 arc..?
  • 抛出异常时查看堆栈可能很有用。如果您自己不调用 respondsToSelector:,则可能会在将 ssp 用作某种代表时发生这种情况。
  • 您遇到的例外是一个非常普遍的例外; 您需要使用调试器设置断点以在抛出异常时停止。 然后您可以查看调用堆栈(正如 Phillip Mills 建议的那样)并找出您的代码正在做什么来触发异常. 那么我们将有足够的信息来解决这个问题。
  • @benzado:我使用代码处理多个方向:[[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"storeSinglePlayerLandscape"] owner:self options:nil]; [self viewDidLoad];会不会是这个问题造成的?

标签: iphone objective-c ios


【解决方案1】:

在 ARC 发布后,有东西在调用您的 ssp。您发布的代码没有说明发生的位置。

最有可能解决问题的一件事是在类声明中保留对 ssp 的成员变量+属性的引用,而不是每次单击按钮时都创建一个新的引用。只需在您的第一个视图控制器加载并重用它时初始化一次。

如果您想进一步调查,可以尝试注释掉设置过渡的块,看看它是否仍然崩溃。可能在 ssp 发布后,navigationcontroller 会进行一些调用。

【讨论】:

  • 感谢您的回复。事实上,我可以通过应用所有可能的解决方案来缩小实际问题的范围。
【解决方案2】:

当一个消息被发送到一个被释放的实例时,一个对象从内存中被释放并且你试图再次使用它。 ARC 必须释放对象,因为它会自动检测到您不再需要它。尝试将以下内容之一添加到您的头文件中。

@property (nonatomic, strong) storeSinglePlayer *ssp;

storeSinglePlayer *__strong ssp;

上面最重要的词是strong。它告诉 ARC 你想保留这个对象供以后使用。

【讨论】:

    【解决方案3】:

    我搞砸了。我正在使用以下代码处理多次旋转:

    [[NSBundle mainBundle] loadNibNamed:[NSString stringWithFormat:@"storeSinglePlayerLandscape"] owner:self options:nil];
    
    [self viewDidLoad];
    

    我现在意识到,这不是最佳做法,因为它会多次调用 viewDidLoad。不过,这并不是问题的真正原因。当商店只显示几次并返回到前一个视图控制器时,它工作正常。但是说在 10-15 次之后,有太多的请求会随产品返回,因此会发送错误,“消息已发送到已释放的实例”。

    我把代码注释掉了,现在可以正常使用了。

    我知道,这是一个非常典型的问题,大多数用户可能不会遇到。但是以防万一,您使用了像我这样的错误代码,可能这些信息有效!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-07-03
      • 2011-07-02
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      • 2011-07-02
      相关资源
      最近更新 更多