2014-08-21 20 views
6

Pracuję nad niektórymi IAP using this tutorial.Program obsługi zakończenia powodujący EXC_BAD_ACCESS, gdy ta sama metoda jest wywoływana dwukrotnie

pierwsze I pobrania produktów z tym:

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

pomocniczy działa następujące:

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler { 

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

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

Gdy produkty są zwrócone lub nie powiodła się nazywa następujące:

#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; 

} 

Numer
Problem występuje, gdy użytkownik uruchamia pobieranie lub produkty dwa razy. Na przykład produkty pobierania są wywoływane w viewDidLoad, ale jeśli użytkownik ma złe/wolne połączenie i nawiguje z dala, a następnie z powrotem do kontrolera. Początkowe pobieranie nie zostanie anulowane, dlatego są dwa uruchomione.

Uważam, że problem występuje, gdy drugi jest zwracany, a wskaźnik się zmienił/nie istnieje/jest uszkodzony.

EXC_BAD_ACCESS 2 kod błędu pojawia się na właściwej linii:

_completionHandler(YES, skProducts); 

LUB

_completionHandler(NO, nil); 

Odpowiedz

14

Masz rację. Nie istnieje, gdy zwracana jest druga odpowiedź, ponieważ jest ona usuwana po obsłużeniu pierwszej odpowiedzi: completionHandler = nil.

W takiej sytuacji uważam, że najbezpieczniej zawsze sprawdzić, czy istnieje blok przed wywołaniem go:

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

(i tym samym w -request:didFailWithError:). W bieżącej implementacji wywołanie [[IAPHelper sharedInstance] requestProductsWithCompletionHandler:nil] spowoduje taką samą awarię bez tego sprawdzenia (spróbuj!).

Oprócz tych kontroli bezpieczeństwa, najlepiej anulować pierwsze żądanie, gdy jest to odpowiednie, np. Kiedy użytkownik nawiguje i nie zobaczy odpowiedzi. Również w przypadku -requestProductsWithCompletionHandler: anulowanie istniejącego _productsRequest przed utworzeniem nowego lub sprawdzeniem istniejącego _productsRequest, aby zdecydować, czy utworzyć nowy, byłoby kolejną przydatną warstwą bezpieczeństwa.

+1

Dzięki, użyłem części obu odpowiedzi, ale to było najbliżej. Dodałem także dodatkową metodę '- (void) cancelProductRequest { [_productsRequest cancel]; _productsRequest = nil; } 'która anuluje bieżące żądanie, jeśli odejdzie od tego kontrolera, aby zapisać, że kiedykolwiek istnieje wiele żądań. – StuartM

+0

Świetne @StuartM, zdecydowanie najlepiej anulować żądanie, jeśli go nie potrzebujesz. Cieszę się, że mogłem pomóc! – stefandouganhyde

Powiązane problemy