完成处理程序在两次调用相同方法时导致EXC_BAD_ACCESS

时间:2014-08-21 12:37:37

标签: ios in-app-purchase exc-bad-access storekit skproduct

我正在研究一些IAP using this tutorial

首先我用这个来获取产品:

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

帮助程序运行以下内容:

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {

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

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

当产品退回或失败时,会调用以下内容:

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

}

问题
我们遇到的问题是当用户开始两次获取或产品时。例如,在viewDidLoad上调用fetch产品,但是如果用户具有错误/慢速连接并导航,然后返回控制器。初始提取未被取消,因此有两个正在运行。

我认为问题在于返回第二个并且指针已更改/不存在/已损坏。

EXC_BAD_ACCESS代码2错误发生在相关行:

_completionHandler(YES, skProducts);

OR

_completionHandler(NO, nil);

1 个答案:

答案 0 :(得分:17)

你是对的。在返回第二个响应时它不存在,因为它在处理完第一个响应后被填满:completionHandler = nil

在这种情况下,我发现在调用之前总是检查该块是否最安全:

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

(和-request:didFailWithError:中的相同)。在您当前的实现中,调用[[IAPHelper sharedInstance] requestProductsWithCompletionHandler:nil]将导致相同的崩溃而不进行此检查(尝试它!)。

除了这些安全检查之外,最好在适当的时候取消您的第一个请求,例如当用户导航时,无论如何都不会看到响应。此外,在-requestProductsWithCompletionHandler:中,要么在创建新_productsRequest之前取消现有_productsRequest,要么检查现有{{1}}是否要创建新的{{1}},这将是另一个有用的层安全