Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 9311369
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 19, 20262026-06-19T01:20:49+00:00 2026-06-19T01:20:49+00:00

In my previous apps, there is only one IAP, so I didn’t realized there

  • 0

In my previous apps, there is only one IAP, so I didn’t realized there was problem in my code. Today I have an app with multiple IAP products, and I found the problem.

I followed Troy’s IAP tutorial, and pretty much copied his code. That worked well for my previous apps, as there was only one IAP product in each of those apps. The tutorial uses one IAP product as example, as well. I was trying to post at his blog to ask my question, but my post would be too long and no formatting, plus I think experts here can help me understand more and check if I misunderstood something or missed something.

Now two things I have to handle (unless I missed, the tutorial didn’t mention cases of multiple IAP products).

1, I don’t know if I misunderstood, in the tutorial, there’s a comment for loadStore method, like this

//
// call this method once on startup
//
- (void)loadStore {
    // restarts any purchases if they were interrupted last time the app was open
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    // get the product description (defined in early sections)
    [self requestProUpgradeProductData];
}

So I call this method at the beginning of my app in the ViewController.m file. My understanding is that this method needs check if there was any previous transaction hanging over there and need take care of it at the moment app re-starts. That’s the first statement of this loadStore method. The method continues to call requestProUpgradeProductData, which like this:

- (void)requestProUpgradeProductData {
   NSSet *productIdentifiers = [NSSet setWithObject:@"com.runmonster.runmonsterfree.upgradetopro" ];
    productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

    // we will release the request object in the delegate callback
}

Notice here, the first statement in this method is to get IAP product ID. This is all fine for one-IAP-product apps, since the product ID is fixed, and it’s okay to call loadStore at the beginning of running the app. Actually, loadStore probably has to run at the beginning of running the app, because, here is the second problem.

2, If loadStore runs at the moment a user wants to buy IAP, rather than at the beginning of the app, the catch is when [productRequest start] runs, the following method will run:

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSArray *products = response.products;
    proUpgradeProduct = [products count] == 1 ? [[products firstObject] retain] : nil;
    if (proUpgradeProduct)
    {
    NSLog(@"Product title: %@" , proUpgradeProduct.localizedTitle);
    NSLog(@"Product description: %@" , proUpgradeProduct.localizedDescription);
    NSLog(@"Product price: %@" , proUpgradeProduct.price);
    NSLog(@"Product id: %@" , proUpgradeProduct.productIdentifier);
    }

    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    {
    NSLog(@"Invalid product id: %@" , invalidProductId);
    }

   // finally release the reqest we alloc/init’ed in requestProUpgradeProductData
   [productsRequest release]; //I didn't do this because of ARC

    [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
}

This will run and return response with products. then I need initiate payment, but I AM NOT SURE HRER HOW SHOULD FOLLOWING METHOD BE CALLED. This is the method initiating IAP payment. As I mentioned, once loadStore runs at the beginning of the app, there are “plenty” time for productRequest….response method (right above) to finish and sending back notification, given that users click here and there for a second. And as I said, for one-IAP-product app, that’s fine, I can specify the product ID at the beginning. Now for an app with multiple-IAP-product, I need present multiple products to users, and users choose one of them. Right after this, I need two things in order: A, specify which IAP product, via loadStore -> productRequest method (right above), and B, call the following method to initiate payment.

- (void)purchaseProUpgrade
{
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

However, productRequest…..response method may not return yet at the moment I call the payment initiating method. I would not be able to initiate payment. I was thinking to put a delay function in between with a second or so, but I think this approach would be fundamentally wrong. However, how to solve the problem?

Can anyone help here?

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-19T01:20:50+00:00Added an answer on June 19, 2026 at 1:20 am

    The key thing is that you cannot allow the user to purchase anything until you get the response back from the productsRequest. First, initWithProductIdentifiers: takes a set of identifiers. So, on app startup or any other time prior to presenting the purchase option to the user, you call it with the identifiers/skus for ALL products that you may allow the user to purchase. Calling it on startup seems wasteful to me but it should also work and may be the only option for some apps.

    Only after you get the productsRequest:didReceiveResponse: callback containing the product objects do you allow the user to click/touch or otherwise invoke the purchase action for that product. You have to check the responses to ensure that the product is present before allowing the user to attempt the purchase. I have a purchase screen and when the user enters it, I invoke the productsRequest with all products relevant to the application’s current state (e.g. omitting already purchase items or restricting products by level). I also create the purchase screen but I do not populate it with any products. In the response delegate, I actually populate the screen with the purchasable objects. That way, the user cannot attempt to buy an invalid product.

    When the user clicks/taps, you use the product object from the response to create the payment object using :

    [SKPayment paymentWithProduct:product]
    

    Note that this is a change from your current setup which uses paymentWithProductIdentifier: – a deprecated method.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

In one of my previous apps I needed to add controls to a flowlayoutpanel
I previous recieved help with a problem, getting a multiple option select form to
I have changed one of my apps to use URL Rewrite 1.1 in IIS7.5
I am going to develop an android app, but unlike my previous apps, this
Problem: I'm an app developer and my boss asked me how many times one
I know there has been previous talk on here about screencasting tools/apps, however I
I have twitter integrated to iPhone app by previous developer. Also have twitter consumer
Some mac apps, like iTunes and Spotify, react to the play/pause/next/previous buttons on some
In previous versions of Excel there was a registry entry that you could create
From previous post, I learnt that for there are two ways, at least, to

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.