Jauzee
Jauzee

Reputation: 118

How right to request IAP price

I use one class to purchase & download books. In viewWillAppear I request the localized price for product to show it in UILabel:

   class Books: UIViewController, ... {

     override func viewWillAppear(animated: Bool) {

     requestProductInfo()


     }

     func requestProductInfo() {

          if SKPaymentQueue.canMakePayments() {
            var productIdentifiers: NSSet = NSSet(object: "com.jauzee.myProduct")
            var productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as Set<NSObject>)
            productRequest.delegate = self
            productRequest.start()
          }

        }
   }

The problem is: If I close Books VC and requestProductInfo() is in progress application crashes (with errors, that I can't read).

How can I make closing Books VC safe while requesting product info?

I've been try to make special helper-class for requesting product information:

import Foundation
import StoreKit

class InAppHelper: NSObject, SKProductsRequestDelegate {

    func requestProductPrice() {
        if SKPaymentQueue.canMakePayments() {
            var productIdentifiers: NSSet = NSSet(object: "com.jauzee.myProduct")
            var productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as Set<NSObject>)
            productRequest.delegate = self
            productRequest.start()
        }
    }


    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
        var products: NSArray = response.products
        var count : Int = response.products.count
        if count > 0 {
            var product: SKProduct = products[0] as! SKProduct
            userDefaults.setObject(product.localizedPrice(), forKey: "localizedPrice");
        }
    }
}

But when I call requestProductPrice() from Books VC:

class Books: UIViewController, ... {

 override func viewWillAppear(animated: Bool) {
    ...
    var inAppHelper = InAppHelper()
    inAppHelper.requestProductPrice()
    ...
 }
}

It doens't call didReceieveResponse delegate method.

How rightly request In-App-Purchase product info? Or how to make class to request that info?

UPDATE: I try to:

deinit {
    SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
    productRequest?.delegate = nil
    productRequest?.cancel()
}

in Books VC, but it doesn't help. Does this mean that the problem lies elsewhere (not in dealloc VC, but in something else...)? Or I doens't do this right way (deinit)?

Upvotes: 2

Views: 188

Answers (1)

Steve Madsen
Steve Madsen

Reputation: 13791

In your first example, your Books view controller is deallocated when you navigate away from it. You haven't stopped the product request, and more importantly, haven't unset the delegate you assigned to the product request. When the request completes, it tries to call your now deallocated Books view controller. This is why the app crashes.

To fix this, you'd need to hold on to a reference to the request so that you could set the delegate to nil before the Books view controller goes away.

What I've typically done in this situation in the past is allocate a helper instance early in the app's lifetime. The helper requests all of the IAP products a launch time. Since it's never deallocated, it serves as the request delegate. You can make the products available via a read-only property to your Books view controller. Since it's never deallocated, you won't have the crashing problem you do in your first example. Another advantage of a long-lived helper instance is that you'll generally have all of the product info by the time a view controller wants to display it. There won't be a delay when showing the IAP list (you already have them) and you don't need to implement the -didReceiveResponse delegate on your view controller (as you're attempting to do in your second example).

Upvotes: 2

Related Questions