Reputation: 1318
I notice that if you enter my Store View in my app (asking apple for product) and then close the store view before all the products have been loaded from apple it crashes.
2012-11-05 12:32:08.420 Bellman[71368:c07] Dealloc inAppManager
2012-11-05 12:32:13.788 Bellman[71368:c07] *** -[InAppPurchaseManager respondsToSelector:]: message sent to deallocated instance 0x8e85a50
As you can see in my code i'm calling removeTransactionObserver:
when dealloc is called. And as you can see in the log above dealloc is being called 5 seconds before the app is crashing. From what i understand the default queue is trying to call productsRequest: didReceiveResponse:
even tho i've removed my self as observer?
- (void)requestProUpgradeProductData:(NSSet*)productIdentifiers
{
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.productsRequest.delegate = self;
[self.productsRequest start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *products = response.products;
NSLog(@"%@",products);
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
NSLog(@"Invalid product id: %@" , invalidProductId);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
[[self delegate] didLoadStore:response.products];
}
- (void)loadStore:(NSSet*)productIdentifiers
{
// restarts any purchases if they were interrupted last time the app was open
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
// get the product description (defined in early sections)
[self requestProUpgradeProductData:productIdentifiers];
NSLog(@"Unfinished Transactions: [%i]", [[SKPaymentQueue defaultQueue].transactions count]);
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchase:(SKProduct*)product {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
NSLog(@"Subscription bought");
}
- (void)provideContent:(SKPaymentTransaction *)transaction
{
NSLog(@"Asking user to register Database");
[[self delegate] provideContent:transaction];
}
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSLog(@"Removeing recipt");
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
if (wasSuccessful)
{
[[self delegate] didMakePurchase:transaction.payment.productIdentifier];
// send out a notification that we’ve finished the transaction
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];
}
else
{
// send out a notification for the failed transaction
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
[self recordTransaction:transaction];
[self provideContent:transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
}
- (void)completePurches:(SKPaymentTransaction *)transaction {
NSLog(@"EVERYTHING IS DONE!");
[[NSUserDefaults standardUserDefaults] removeObjectForKey:@"unfinishedReceipt"];
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
[[self delegate] didReciveAppStoreError:transaction.error.localizedDescription];
// Optionally, display an error here.
}
[[self delegate] didCancelPurches];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
NSLog(@"Completed transcation");
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"Failed transcation: %@",transaction.error);
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Restore transcation: %@",transaction.payment.productIdentifier);
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(@"ID: %@",transaction.transactionIdentifier);
break;
default:
break;
}
}
}
-(void)didVerifyNewRecipt:(SKPaymentTransaction *)recipt wasNewRecipit:(BOOL)status {
if (status) {
NSLog(@"Was new recipt showing interface");
[self completeTransaction:recipt];
} else {
NSLog(@"Was old Receipt");
[self completePurches:recipt];
[[self delegate] didFindOldReceipt];
}
}
-(void)didReciveError:(NSString *)error {
NSLog(@"ERROR! %@",error);
}
-(void)dealloc {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
NSLog(@"Dealloc inAppManager");
}
Upvotes: 0
Views: 865
Reputation: 1318
When i was about to hit "Ask Question" it just figured it out. Since i have not found an answer for this on internet i gonna share my solution.
Since SKProductsRequest
is not a part of the SKPaymentQueue and SKProductsRequest
implements their own delegate you need to remove the delegate you set on the SKProductsRequest.
-(void)dealloc {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
self.productsRequest.delegate = nil; // <----- Solution
NSLog(@"Dealloc inAppManager");
}
Upvotes: 2