Set Value Of Product

I am setting up in app purchases in my app to remove ads. I am following a youtube tutorial. In the tutorial on line 3 it does not provide a value to product. I know that that is the product of removing the ads. However I don't know what to set that value as.


I was told to do this:

product = SKProduct(productID)


But I got an error.


Here is my code:

class HomeViewController: UIViewController, SKPaymentTransactionObserver, SKProductsRequestDelegate {  
var product : SKProduct?  
    var productID = "NolanZ.Winer.removeads"  
@IBAction func removeAds(_ sender: Any) {  
        let payment = SKPayment(product: product!) //getting error here  
        SKPaymentQueue.default().add(payment)  
    }  
 func getPurchaseInfo() {  
        if SKPaymentQueue.canMakePayments() {  
            let request = SKProductsRequest(productIdentifiers: NSSet(objects: self.productID) as! Set)  
            request.delegate = self  
            request.start()  
        }  
    }  
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {  
        var products = response.products  
        if (products.count == 0) {  
            SVProgressHUD.showError(withStatus: "Check Your Internet Connection And Try Again")  
        } else {  
            buyButton.isEnabled = true  
        }  
        let invalids = response.invalidProductIdentifiers  
        for product in invalids {  
            SVProgressHUD.showError(withStatus: "Product Not Found")  
        }  
    }  
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {  
        for transaction in transactions {  
            switch transaction.transactionState {  
            case SKPaymentTransactionState.purchased:  
                SKPaymentQueue.default().finishTransaction(transaction)  
                SVProgressHUD.showSuccess(withStatus: "Purchase Successful")  
                buyButton.isEnabled = false  
                adsRemoved = true  
                defaults.set(adsRemoved, forKey: "ads")  
            case SKPaymentTransactionState.failed:  
                SKPaymentQueue.default().finishTransaction(transaction)  
                SVProgressHUD.showError(withStatus: "Purchase Not Successful")  
            default:  




                break  
            }  
        }  
    }  
}

Thanks for all help!

Accepted Reply

I do not have much experience using In-App Purchase,

but as far as I read the Apple's docs, instances of `SKProduct` are held in `response` of the method `productsRequest(_:didReceive:)`.

    @IBAction func removeAds(_ sender: Any) {
        if let product = product { //### You should better check if `product` is nil or not here.
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(payment)
            //You should better update the UI for `processing` state...
        } else {
            //Show some alerts that product is not set...
            print(#function, "`product` is nil")
        }
    }

    func getPurchaseInfo() {
        if SKPaymentQueue.canMakePayments() {
            let request = SKProductsRequest(productIdentifiers: [self.productID]) //Better avoid using `NSSet`
            request.delegate = self
            request.start()
        }
    }

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let products = response.products
        if products.isEmpty {
            SVProgressHUD.showError(withStatus: "Check Your Internet Connection And Try Again")
        } else {
            buyButton.isEnabled = true
            product = products[0] //### You need to set the product in `response.products` to your `product`
        }
        let invalids = response.invalidProductIdentifiers
        if !invalids.isEmpty { //I believe you have no need to repeat `showError`...
            SVProgressHUD.showError(withStatus: "Product Not Found")
        }
    }


One more, this topic is not appropriate for Xcode IDE and Editor. Better visit In-App Purchase Product preparation, Validation, Transactions.

Replies

Where in code did you put:

    product = SKProduct(productID)

I could not find it.


Please, show the complete SKProduct class or struct


In anycase, you should make your code more robust:


@IBAction func removeAds(_ sender: Any) {  
    
     if let product = product {
        let payment = SKPayment(product: product)      //  remove unwrap ;    getting error here  
        SKPaymentQueue.default().add(payment)  
     }
  } 

Xcode will not let me do

product = SKProduct(productID)


It says SKProduct cant have ()


I don’t understand what you mean by the SKProduct class or struct. I don’t think I have that.


Sorry I have never tried in app purchases before. Thanks again for your help!

I do not have much experience using In-App Purchase,

but as far as I read the Apple's docs, instances of `SKProduct` are held in `response` of the method `productsRequest(_:didReceive:)`.

    @IBAction func removeAds(_ sender: Any) {
        if let product = product { //### You should better check if `product` is nil or not here.
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(payment)
            //You should better update the UI for `processing` state...
        } else {
            //Show some alerts that product is not set...
            print(#function, "`product` is nil")
        }
    }

    func getPurchaseInfo() {
        if SKPaymentQueue.canMakePayments() {
            let request = SKProductsRequest(productIdentifiers: [self.productID]) //Better avoid using `NSSet`
            request.delegate = self
            request.start()
        }
    }

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        let products = response.products
        if products.isEmpty {
            SVProgressHUD.showError(withStatus: "Check Your Internet Connection And Try Again")
        } else {
            buyButton.isEnabled = true
            product = products[0] //### You need to set the product in `response.products` to your `product`
        }
        let invalids = response.invalidProductIdentifiers
        if !invalids.isEmpty { //I believe you have no need to repeat `showError`...
            SVProgressHUD.showError(withStatus: "Product Not Found")
        }
    }


One more, this topic is not appropriate for Xcode IDE and Editor. Better visit In-App Purchase Product preparation, Validation, Transactions.

The usual flow is

0) the user asks to make a purchase

1) you create an SKProductsRequest (and do a 'start') with a set of possible productID's (or just the one that the user wants to purchase)

2) that 'start' will return with a call to productsRequest:didReceiveResponse that contains an array of products (response.products). Each object in the array response.products is a valid product for sale at the store. Each product contains information like localized price and the productID.

3) once you get an acceptable response from didReceiveResponse you create an SKPayment object that contains one of those objects in the array response.products. (Usually there is only one product. But you might be offering the user a set of products - like a level 1 and a level 2 - so you might take all of the response.products objects and present them to the user and let the user chose one.) You then submit that SKPayment object to the SKPaymentQueue defaultQueue with an addPayment.


So the short answer to your question is that you get the SKPayment product object from within the didReceiveResponse by selecting one of the objects in the response.products array.


The SVProgressHUD has nothing to do with any of this - it's somethinge extra someone has shown on utube and github.



And there is a forum for In App Purchase questions under System Frameworks