2011-01-24 18 views
5

Tengo problemas para implementar InAppPurchase. Mi implementación de compra está en el controlador de vista modal (AppUpgradeViewController), que presento desde otra vista modal. Lo hago así:iPhone - SKProductsRequest y "mensaje enviado a instancia desasignada"

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

Entonces, en mi opinión actualización hago lo siguiente:

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

Luego he implementado

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

donde hago:

[self.productsRequest release]; 

y luego tengo otros métodos requeridos.

El problema es cuando muestro modal, y despedir rápidamente a continuación, después de unos segundos me dieron el siguiente en la consola (Encendí NSZombieEnabled):

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

supongo que es algo con esa solicitud de productos, pero no sé cómo depurarlo o solucionarlo. Parece que la respuesta a la solicitud llega a este controlador justo después de que se descarta (y se desasigna), pero no sé cómo evitar que reciba mensajes después de cerrar/tratarloc. ¡Gracias por cualquier ayuda!

+0

Estoy teniendo el mismo problema, pero ninguna de las soluciones a continuación me funciona. Tengo ARC habilitado. ¿Alguna sugerencia? – mvb

Respuesta

0

¿Es porque usted está haciendo esto:

[appUpgradeViewController release]; 

demasiado pronto?

Trate de hacerlo en el método dealloc de cualquier clase en la que lo esté asignando. Siempre que no esté distribuyendo más de una vez, por supuesto. Esto también requeriría que mueva su declaración al encabezado de la clase.

+0

No creo que lo haga demasiado temprano. Es probable que algo llame al método de ese controlador, cuando definitivamente no debe. – Marcin

2

Supongo que es porque ha lanzado su productsRequest, pero parece que no ha establecido el puntero en nil, lo que significa que todavía apunta a la ubicación de memoria ahora no válida.

¿Cómo se define la propiedad productsRequest? Si se tiene la opción retain, entonces en lugar de:

[self.productsRequest release]; 

que tiene que hacer:

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

si tiene la opción assign, entonces usted tiene que hacer:

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

Se define así: @property (no atómico, retener) SKProductsRequest * productsRequest; – Marcin

+0

En ese caso, todo lo que necesita hacer es 'self.productsRequest = nil;'. Do ** not ** do '[self.productsRequest release];', esto dará como resultado errores de memoria. – DarkDust

+0

Se define así: @property (no atómica, retener) SKProductsRequest * productsRequest; Pero sólo soltar su parte "- (void) productsRequest: (SKProductsRequest *) Solicitud de didReceiveResponse: (SKProductsResponse *) Respuesta" método, así que no es liberado hasta que el controlador recibe la respuesta. Si dejo el modal inmediatamente, antes de que el controlador reciba una respuesta, esto no sucederá. – Marcin

4

Probablemente se olvidó de anular su delegado de solicitud en AppUpgradeViewController 's dealloc:

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

gracias, guardaste mi día guardado !!!!! : D – SpaceDog

9

Tuve el mismo problema. No con una vista modal, pero con una vista presionada en la pila del controlador de navegación. Cuando navegué rápidamente antes de cargar la información de mi producto a través del SKProductsRequest, también arrojó una excepción message sent to deallocated instance. Lo resolví llamando al método cancel (vea reference) en mi objeto SKProductsRequest.

Adicional a esto, también puse el delegado de nil.

Esta es mi pedido del producto:

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

y esto es lo que se llama en el método dealloc para cancelarla.

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

También elimina el observador de la SKPaymentQueue como se describe en this answer for another question.

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

Eso es perfecto ... .trabajado como un encanto para mí;) –

+0

Esto tomó tanto tiempo para averiguarlo. Permitir que los objetos de Zombie atraparan esto que me estaba tirando '- [IAPurchaseViewController retener]: mensaje enviado a la instancia desasignada'. ¡Gracias! – alexgophermix

0

Swift 3

Es una buena idea para cerrar la solicitud si la que lo inició. Esta es una forma segura de hacerlo en 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 
    } 
Cuestiones relacionadas