iPhone - SKProductsRequest and "message sent to deallocated instance"
I got troubles implementing InAppPurchase. My implementation of purchase is in modal view controller (AppUpgradeViewController), that I present from another modal view. I do it like this:
AppUpgradeViewController * appUpgradeViewController = [[AppUpgradeViewController alloc] init];
appUpgradeViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
appUpgradeViewController.delegate = self;
[self presentModalViewController:appUpgradeViewController animated:YES];
[appUpgradeViewController release];
Then, in my upgrade view I do the following:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
NSSet *productIdentifiers = [NSSet setWithObject:kInAppPurchaseProUpgradeProductId];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.productsRequest.delegate = self;
[productsRequest start];
Then I have implemented
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
where I do:
[self.productsRequest release];
and then I have other required methods.
The problem is when I show modal, and quickly dismiss it then after few seconds i got the following on console (I turned on NSZombieEnabled):
*** -[AppUpg开发者_JAVA百科radeViewController respondsToSelector:]: message sent to deallocated instance 0x2e91f0
I suppose that it's something with that product request, but I don't know how to debug or fix it. It seems that the answer for request comes to this controller just after it's dismissed (and deallocated), but I don't know how to prevent it from receiving messages after dismiss/dealloc. Thanks for any help!
I had the same problem. Not with a modal view, but with a pushed view on the navigation controller stack. When I quickly navigated back before my product information was loaded via SKProductsRequest
, it also throws me an message sent to deallocated instance
exception. I solved this by calling the cancel
method (see reference) on my SKProductsRequest object.
Additional to this I also set the delegate to nil
.
This is my product request:
NSSet *productIdentifiers = [NSSet setWithObject:@"MY_IDENTIFIER"];
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
and this is what I called in the dealloc method to cancel it.
productsRequest.delegate = nil;
[productsRequest cancel];
productsRequest = nil;
I also removed the observer from the SKPaymentQueue
like described in this answer for another question.
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
You probably forgot to nil your request delegate in AppUpgradeViewController
's dealloc
:
- (void)dealloc {
...
productsRequest.delegate = nil;
[productsRequest release], productsRequest = nil;
...
[super dealloc];
}
I guess that's because you have released your productsRequest, but it seems you haven't set the pointer to nil
which means it's still pointing at the now-invalid memory location.
How is the productsRequest
property defined ? If it has the retain
option, then instead of:
[self.productsRequest release];
you need to do:
self.productsRequest = nil; // Property will do the release for you.
If it has the assign
option, then you need to do:
[self.productsRequest release];
self.productsRequest = nil; // Or else some might access this pointer,
// which now might point to nirvana.
Is it because you're doing this:
[appUpgradeViewController release];
too early?
Try doing it in the dealloc method of whatever class you're allocing it in. Providing you're not allocing it more than once, of course. This would also require you to move your declaration into the class header.
Swift 3
It's a good idea to close the request if you started it. This is a safe way to do it in 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
}
精彩评论