我正在研究一些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);
答案 0 :(得分:17)
completionHandler = nil
。
在这种情况下,我发现在调用之前总是检查该块是否最安全:
if (_completionHandler) {
_completionHandler(YES, skProducts);
_completionHandler = nil;
}
(和-request:didFailWithError:
中的相同)。在您当前的实现中,调用[[IAPHelper sharedInstance] requestProductsWithCompletionHandler:nil]
将导致相同的崩溃而不进行此检查(尝试它!)。
除了这些安全检查之外,最好在适当的时候取消您的第一个请求,例如当用户导航时,无论如何都不会看到响应。此外,在-requestProductsWithCompletionHandler:
中,要么在创建新_productsRequest
之前取消现有_productsRequest
,要么检查现有{{1}}是否要创建新的{{1}},这将是另一个有用的层安全