App crashed with UITabBarController and In App Purchases

in-app-purchase, ios, uitabbarcontroller

Solution

There is a problem in the implementation of the `LAInAppHelper` in the tutorial that you linked: the helper treats your application as non-concurrent.

Here is what is going on: the shared instance of `LAInAppHelper` has a `sharedInstance`, which owns `_completionHandler` (among other things).

The `requestProductsWithCompletionHandler:` method assigns `_completionHandler` a copy of the block that has been passed in. This is OK for the first request, but if another request is "in flight", the completion block of that other request will be released by ARC due to this reassignment. If the tab to which you switch starts a concurrent request, the initial request will come back to a released block, causing an undefined behavior, and possibly a crash.

To fix this problem, you need to split the class in two - one part holding items common to all requests (namely, `_productIdentifiers` and `_purchasedProductIdentifiers`) and the request-specific ones (`_productsRequest` and `_completionHandler`).

The instance of the first class (let's call it `LAInAppHelper`) remains shared; instances of the second class (let's call it `LAInAppHelperRequest`) are created per-request inside the `requestProductsWithCompletionHandler:` method.

-(id)initWithHelper:(LAInAppHelper*)helper
    andCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
    if (self = [super init]) {
        _completionHandler = [completionHandler copy];
        _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:helper.productIdentifiers]; // You will need to make productIdentifiers a property
        _productsRequest.delegate = self;
        [_productsRequest start];
    }
    return self;
}

You will need to create a block that wraps the `_completionHandler`, too, like this:

- (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {
    __block LAInAppHelperRequest *req = [[LAInAppHelperRequest alloc] initWithHelper:self andCompletionHandler:^(BOOL success, NSArray *products) {
         completionHandler(success, products);
         req = nil;
    }];
}

Problem

My app used in app purchases and my references here. When i am loading products from server by a block, at the same time I switch to other tab inside UITabBarController and app crashed when products loaded This is my code ``` //Load products from server [[LAInAppHelper sharedInstance] requestProductsWithCompletionHandler:^(BOOL success, NSArray *products) { if (success) { // even i do nothing in here app till crashed } }]; ``` If I delete this lines I can switch between any tab. Nothing throw by app when crashed, even i enable Zombie objects. Just bad access

Original source