iPhone - SKProductsRequest 和“发送到已释放实例的消息”

Posted

技术标签:

【中文标题】iPhone - SKProductsRequest 和“发送到已释放实例的消息”【英文标题】:iPhone - SKProductsRequest and "message sent to deallocated instance" 【发布时间】:2011-06-14 12:14:59 【问题描述】:

我在实施 InAppPurchase 时遇到了麻烦。我的购买实现是在模态视图控制器(AppUpgradeViewController)中,我从另一个模态视图呈现。我是这样做的:

AppUpgradeViewController * appUpgradeViewController = [[AppUpgradeViewController alloc] init];
appUpgradeViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
appUpgradeViewController.delegate = self;
[self presentModalViewController:appUpgradeViewController animated:YES];
[appUpgradeViewController release];

然后,在我的升级视图中,我执行以下操作:

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
NSSet *productIdentifiers = [NSSet setWithObject:kInAppPurchaseProUpgradeProductId];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.productsRequest.delegate = self;
[productsRequest start];

那我已经实现了

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response

我在哪里:

[self.productsRequest release];

然后我还有其他需要的方法。

问题是当我显示模态并快速关闭它时,几秒钟后我在控制台上得到以下信息(我打开了 NSZombieEnabled):

*** -[AppUpgradeViewController respondsToSelector:]: message sent to deallocated instance 0x2e91f0

我想这与产品请求有关,但我不知道如何调试或修复它。似乎请求的答案是在它被解除(和解除分配)之后才出现在这个控制器上的,但我不知道如何防止它在解除/解除分配后接收消息。 感谢您的帮助!

【问题讨论】:

我遇到了同样的问题,但以下解决方案都不适合我。我启用了 ARC。有什么建议吗? 【参考方案1】:

我遇到了同样的问题。不是模式视图,而是导航控制器堆栈上的推送视图。当我在通过SKProductsRequest 加载我的产品信息之前快速导航回来时,它也会引发message sent to deallocated instance 异常。我通过在我的 SKProductsRequest 对象上调用cancel 方法(参见reference)解决了这个问题。

除此之外,我还将代理设置为nil

这是我的产品要求:

NSSet *productIdentifiers = [NSSet setWithObject:@"MY_IDENTIFIER"];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];

这就是我在 dealloc 方法中调用来取消它的。

productsRequest.delegate = nil;
[productsRequest cancel];
productsRequest = nil;

我还从SKPaymentQueue 中删除了观察者,如this answer for another question 中所述。

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

【讨论】:

这花了很长时间才弄清楚。启用 Zombie 对象捕捉到这让我失望了-[IAPurchaseViewController retain]: message sent to deallocated instance。谢谢! 我不明白为什么您(和我)在取消期间必须nil 代表。它必须在所有引用都消失后立即消失,但是有些东西让它与委托引用一起保持活跃,以便回调......【参考方案2】:

您可能忘记在AppUpgradeViewControllerdealloc 中设置您的请求委托:

- (void)dealloc 
   ...
   productsRequest.delegate = nil;
   [productsRequest release], productsRequest = nil;
   ...
   [super dealloc];

【讨论】:

【参考方案3】:

我猜那是因为您已经发布了您的 productsRequest,但您似乎没有将指针设置为 nil,这意味着它仍然指向现在无效的内存位置。

productsRequest 属性是如何定义的?如果它有retain 选项,那么代替:

[self.productsRequest release];

你需要做的:

self.productsRequest = nil; // Property will do the release for you.

如果它有assign 选项,那么你需要这样做:

[self.productsRequest release];
self.productsRequest = nil; // Or else some might access this pointer,
                            // which now might point to nirvana.

【讨论】:

定义如下:@property (nonatomic, retain) SKProductsRequest * productsRequest; 在这种情况下,您只需self.productsRequest = nil;。不要不要[self.productsRequest release];,这会导致内存错误。 定义如下:@property (nonatomic, retain) SKProductsRequest * productsRequest;但是我只在“- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response”方法中发布它,所以直到控制器收到响应才发布。如果我在控制器收到响应之前立即关闭模式,这将不会发生。 但我尝试做“[self.productsRequest release];”在我的 dealloc 方法中,错误是:“*** -[SKProductsRequest release]: message sent to deallocated instance 0x20c010”。我在 dealloc 中也试过这个:“self.productsRequest.delegate = nil;”,但错误是:“*** -[SKProductsRequest setDelegate:]: message sent to deallocated instance 0x2f3090”。当我只做“productsRequest = nil;”时在 dealloc 中,我遇到与之前相同的错误:“*** -[AppUpgradeViewController respondsToSelector:]: message sent to deallocated instance 0x2f9590” 终于解决了!我认为我的 dealloc 方法中正确的指令集是: self.productsRequest.delegate = nil; [self.productsRequest 取消]; self.productsRequest = nil; [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];【参考方案4】:

是不是因为你这样做:

[appUpgradeViewController release]; 

太早了?

尝试在您分配它的任何类的 dealloc 方法中执行此操作。 当然,前提是您不会多次分配它。这还需要您将声明移动到类头中。

【讨论】:

我不认为我做得太早了。很可能有些东西正在调用该控制器的方法,但绝对不能。【参考方案5】:

斯威夫特 3

如果您启动了请求,最好关闭它。这是在 Swift 中执行此操作的安全方法。

    // strong reference at top of class
    var productRequest: SKProductsRequest!

    // at some point you will fetch products

    // on deallocating the window
    if productRequest != nil 
        productRequest.cancel()
        productRequest.delegate = nil
    

【讨论】:

以上是关于iPhone - SKProductsRequest 和“发送到已释放实例的消息”的主要内容,如果未能解决你的问题,请参考以下文章

在 iphone 5 和 iphone 6 中动态设置字体大小

Surface Pro4链接不上iphone手机的热点

iphone13和12外观的区别 iphone13和iphone12对比哪个好

为 iPhone 和 iPhone 4 开发之间有啥变化?

iPhone 5 与 iPhone 4 的图像命名

设置图像以适合 iPhone 5 和 iPhone 6