2011-01-24 10 views
5

Ho avuto problemi nell'implementare InAppPurchase. La mia implementazione dell'acquisto è in modal view controller (AppUpgradeViewController), che presento da un'altra vista modale. Lo faccio in questo modo:iPhone - SKProductsRichiesta e "messaggio inviato all'istanza deallocata"

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

Poi, a mio avviso di aggiornamento faccio la seguente:

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

Poi ho implementato

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

dove faccio:

[self.productsRequest release]; 

e quindi ho altri metodi richiesti.

Il problema è quando mostro modali, e rapidamente respingerlo poi dopo pochi secondi ho ottenuto il seguente su console (ho acceso NSZombieEnabled):

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

Suppongo che sia qualcosa con la richiesta del prodotto, ma non so come eseguire il debug o risolvere il problema. Sembra che la risposta alla richiesta arrivi a questo controller subito dopo che è stato eliminato (e deallocato), ma non so come impedirgli di ricevere messaggi dopo il respingimento/dealloc. Grazie per l'aiuto!

+0

Ho lo stesso problema, ma nessuna delle soluzioni seguenti funziona per me. Ho abilitato ARC. Eventuali suggerimenti? – mvb

risposta

0

È perché si sta facendo questo:

[appUpgradeViewController release]; 

troppo presto?

Provare a farlo nel metodo dealloc di qualunque classe si stia assegnando. Provando che non lo si sta allocando più di una volta, ovviamente. Ciò richiederebbe anche di spostare la dichiarazione nell'intestazione della classe.

+0

Non penso di farlo troppo presto. È probabile che qualcosa stia chiamando il metodo di quel controller, quando assolutamente non deve. – Marcin

2

Immagino sia perché hai rilasciato i tuoi prodottiRichiesta, ma sembra che tu non abbia impostato il puntatore su nil il che significa che sta ancora puntando alla posizione di memoria ora non valida.

Come viene definita la proprietà productsRequest? Se si ha la possibilità retain, allora invece di:

[self.productsRequest release]; 

è necessario fare:

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

Se si ha la possibilità assign, allora avete bisogno di fare:

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

È definito in questo modo: @property (nonatomic, retain) SKProductsRequest * productsRequest; – Marcin

+0

In tal caso, tutto ciò che devi fare è 'self.productsRequest = nil;'. Do ** not ** do' [self.productsRequest release]; ', questo si tradurrà in errori di memoria. – DarkDust

+0

È definito in questo modo: @property (nonatomic, retain) SKProductsRequest * productsRequest; Ma lo rilascino solo nel "- (void) productsRequest: (SKProductsRequest *) request didReceiveResponse: (SKProductsResponse *) response", quindi non viene rilasciato finché il controller non riceve risposta. Se esco dal modale immediatamente, prima che il controller riceva la risposta, ciò non accadrà. – Marcin

4

Probabilmente hai dimenticato di annullare la tua richiesta delegato in AppUpgradeViewController's dealloc:

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

grazie, si risparmia salvato la giornata !!!!! : D – SpaceDog

9

Ho avuto lo stesso problema. Non con una vista modale, ma con una vista spinto sullo stack del controller di navigazione. Quando ho rapidamente navigato indietro prima che le mie informazioni sul prodotto sono state caricate tramite SKProductsRequest, mi lancia anche un'eccezione message sent to deallocated instance. Ho risolto questo problema chiamando il metodo cancel (vedere reference) sul mio oggetto SKProductsRequest.

Oltre a ciò, ho impostato il delegato su nil.

Questa è la mia richiesta di prodotto:

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

e questo è quello che ho chiamato nel metodo dealloc per annullarla.

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

Ho anche rimosso l'osservatore dal SKPaymentQueue come descritto in this answer for another question.

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; 
+1

Questo è perfetto ... .worked come un fascino per me;) –

+0

Questo ci è voluto così tanto tempo per capire. Abilita gli oggetti Zombie catturati da ciò che mi stava buttando via '- [IAPurchaseViewController retain]: messaggio inviato all'istanza deallocata'. Grazie! – alexgophermix

0

Swift 3

E 'una buona idea per chiudere la richiesta se si è iniziato. Questo è un modo sicuro per farlo 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 
    } 
Problemi correlati