2014-08-21 19 views
6

Tôi đang làm việc trên một số IAP using this tutorial.Trình xử lý hoàn thành gây EXC_BAD_ACCESS khi cùng một phương thức được gọi hai lần

Trước hết tôi lấy sản phẩm với điều này:

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

Các helper chạy như sau:

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler { 

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

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

Khi sản phẩm được trả lại hoặc thất bại sau được gọi là:

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

} 

Số phát hành
Vấn đề chúng tôi gặp phải là khi người dùng bắt đầu tìm nạp hoặc sản phẩm hai lần. Ví dụ: các sản phẩm tìm nạp được gọi trên viewDidLoad, nhưng nếu người dùng có kết nối xấu/chậm và điều hướng đi và sau đó quay lại bộ điều khiển. Tìm nạp ban đầu không bị hủy vì vậy có hai lần chạy.

Tôi tin rằng vấn đề là khi thứ hai được trả lại và con trỏ đã thay đổi/không tồn tại/hỏng.

Các EXC_BAD_ACCESS 2 mã lỗi xảy ra trên dòng tương ứng:

_completionHandler(YES, skProducts); 

HOẶC

_completionHandler(NO, nil); 

Trả lời

14

Bạn nói đúng. Nó không tồn tại khi phản hồi thứ hai được trả về vì nó được trả sau khi đáp ứng đầu tiên được xử lý: completionHandler = nil.

Trong tình huống này, tôi thấy nó an toàn nhất để luôn kiểm tra xem khối tồn tại trước khi gọi nó:

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

(và giống nhau ở -request:didFailWithError:). Trong quá trình thực hiện hiện tại của bạn, gọi số [[IAPHelper sharedInstance] requestProductsWithCompletionHandler:nil] sẽ gây ra sự cố tương tự mà không cần kiểm tra này (hãy thử nó!).

Trên đầu trang của các kiểm tra an toàn này, tốt nhất bạn nên hủy yêu cầu đầu tiên của mình khi thích hợp, chẳng hạn như khi người dùng điều hướng và sẽ không thấy phản hồi. Ngoài ra, trong -requestProductsWithCompletionHandler:, hoặc hủy _productsRequest hiện có trước khi tạo mới _productsRequest để quyết định có tạo một cái mới hay không, sẽ là một lớp an toàn hữu ích khác.

+1

Cảm ơn, tôi đã sử dụng các phần của cả hai câu trả lời nhưng điều này là gần nhất. Tôi cũng đã thêm một phương thức bổ sung '- (void) cancelProductRequest { [_productsYêu cầu hủy bỏ]; _productsRequest = nil; } 'hủy bỏ yêu cầu hiện tại nếu chúng điều hướng khỏi bộ điều khiển đó để lưu ở đó bao giờ có nhiều yêu cầu. – StuartM

+0

Great @StuartM, chắc chắn là tốt nhất để hủy yêu cầu nếu bạn không cần nó. Mừng vì tôi có thể giúp! – stefandouganhyde

Các vấn đề liên quan