Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iPhone - SKProductsRequest and "message sent to deallocated instance"

Tags:

iphone

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):

*** -[AppUpgradeViewController 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!

like image 625
Marcin Avatar asked Jan 24 '11 12:01

Marcin


3 Answers

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];
like image 123
H6. Avatar answered Sep 28 '22 15:09

H6.


You probably forgot to nil your request delegate in AppUpgradeViewController's dealloc:

- (void)dealloc {
   ...
   productsRequest.delegate = nil;
   [productsRequest release], productsRequest = nil;
   ...
   [super dealloc];
}
like image 29
Jilouc Avatar answered Sep 28 '22 15:09

Jilouc


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.
like image 34
DarkDust Avatar answered Sep 28 '22 15:09

DarkDust