2014-08-21 11 views
6

Sto lavorando su alcuni IAP using this tutorial.Completamento Handler causando EXC_BAD_ACCESS quando lo stesso metodo viene chiamato due volte

In primo luogo ho recuperare i prodotti con questo:

-(void)fetchAvailableProductsFirstLoad:(BOOL)firstTimeLoading { 
    [[IAPHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) { ... 

L'helper esegue la seguente:

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler { 

    @synchronized(self) { 
     // 1 
     _completionHandler = [completionHandler copy]; 

     // 2 
     _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers]; 
     _productsRequest.delegate = self; 
     [_productsRequest start]; 
    } 
} 

Quando i prodotti sono restituiti o fallito il seguente viene chiamato:

#pragma mark - SKProductsRequestDelegate 

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

    NSLog(@"Loaded list of products..."); 
    _productsRequest = nil; 

    NSArray * skProducts = response.products; 
    for (SKProduct * skProduct in skProducts) { 
     NSLog(@"Found product: %@ %@ %0.2f", 
       skProduct.productIdentifier, 
       skProduct.localizedTitle, 
       skProduct.price.floatValue); 
    } 

    _completionHandler(YES, skProducts); 
    _completionHandler = nil; 

} 

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error { 

    NSLog(@"Failed to load list of products."); 
    NSLog(@"Error: %@",error); 
    _productsRequest = nil; 

    _completionHandler(NO, nil); 
    _completionHandler = nil; 

} 

Problema
0.123.Il problema che si verifica è quando l'utente avvia due volte il recupero o i prodotti. Ad esempio, i prodotti di recupero vengono richiamati su viewDidLoad, ma se l'utente ha una connessione brutto/lento e si allontana e torna al controller. Il recupero iniziale non viene annullato, quindi ne esistono due in esecuzione.

Credo che il problema è quando la seconda viene restituita e il puntatore è cambiato/non esiste/corrotto.

L'EXC_BAD_ACCESS errore di codice 2 si verifica sulla linea in questione:

_completionHandler(YES, skProducts); 

O

_completionHandler(NO, nil); 

risposta

14

Hai ragione. Non esiste quando viene restituita la seconda risposta perché viene cancellata dopo che è stata gestita la prima risposta: completionHandler = nil.

In questo tipo di situazione, lo trovo più sicuro per controllare sempre che il blocco esiste prima di chiamare:

if (_completionHandler) { 
    _completionHandler(YES, skProducts); 
    _completionHandler = nil; 
} 

(e lo stesso in -request:didFailWithError:). Nella tua attuale implementazione, chiamare lo [[IAPHelper sharedInstance] requestProductsWithCompletionHandler:nil] causerebbe lo stesso crash senza questo controllo (provalo!).

In cima a questi controlli di sicurezza, sarebbe meglio cancellare la vostra prima richiesta, se del caso, come quando l'utente naviga e non vedrà la risposta in ogni caso. Inoltre, in -requestProductsWithCompletionHandler:, sia annulla un _productsRequest esistente prima di creare il nuovo o il controllo di un esistente _productsRequest per decidere se creare uno nuovo, sarebbe un altro strato utile di sicurezza.

+1

Grazie, ho usato le parti di entrambe le risposte, ma questo era più vicino. Ho anche aggiunto un altro metodo '- (void) cancelProductRequest { [_productsRequest cancel]; _productsRequest = nil; } 'che annulla la richiesta corrente se si allontana da quel controller per salvare le richieste multiple. – StuartM

+0

Great @StuartM, sicuramente meglio annullare la richiesta se non ne hai bisogno. Felice di poterti aiutare! – stefandouganhyde

Problemi correlati