Reputation: 118
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
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