为什么我的阵列超出范围?

时间:2017-01-27 23:00:20

标签: ios arrays swift in-app-purchase xcode8

我正在尝试合并应用内购买。出于某种原因,我得到一个致命的错误,指出“致命错误:索引超出范围”,其中包含一个包含SKProduct产品的数组。我在应用程序购买中有一个非消费品,但可能决定稍后添加更多。我正在尝试访问PREMIUM_PRODUCT_ID产品,以便我可以进行购买。调用purchaseMyProduct函数时发生错误。为什么iapProducts数组超出范围的任何想法?谢谢你的帮助!
此行purchaseMyProduct(product: iapProducts[0])

上发生致命错误
import UIKit
import StoreKit


class Settings: UIViewController, SKProductsRequestDelegate,
SKPaymentTransactionObserver {

    let PREMIUM_PRODUCT_ID = "---------------"

    var productID = ""
    var productsRequest = SKProductsRequest()
    var iapProducts = [SKProduct]()
    var nonConsumablePurchaseMade = UserDefaults.standard.bool(forKey: "nonConsumablePurchaseMade")



    @IBOutlet weak var adsBtn: UIButton!
    @IBAction func restorePurchase(_ sender: Any) {
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().restoreCompletedTransactions()

        // Check your In-App Purchases
        print("NON CONSUMABLE PURCHASE MADE: \(nonConsumablePurchaseMade)")


        // Fetch IAP Products available
        fetchAvailableProducts()

        UIAlertView(title: "IAP Tutorial",
                    message: "You've successfully restored your purchase!",
                    delegate: nil, cancelButtonTitle: "OK").show()
    }

    @IBAction func review(_ sender: Any) {
        UIApplication.shared.openURL(NSURL(string: "-----------------")! as URL)

    }


    @IBAction func removeAds(_ sender: Any) {
        //UIApplication.shared.openURL(NSURL(string: "----------------")! as URL)

        purchaseMyProduct(product: iapProducts[0])

    }


    override func viewDidLoad() {
        super.viewDidLoad()


        // Do any additional setup after loading the view.


    }

   ...

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        nonConsumablePurchaseMade = true
        UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")

        /*UIAlertView(title: "IAP Tutorial",
                    message: "You've successfully restored your purchase!",
                    delegate: nil, cancelButtonTitle: "OK").show()*/
    }

    func fetchAvailableProducts()  {

        // Put here your IAP Products ID's
        let productIdentifiers = NSSet(objects:
                                       PREMIUM_PRODUCT_ID
        )

        productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
        productsRequest.delegate = self
        productsRequest.start()
    }

    func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
        if (response.products.count > 0) {
            iapProducts = response.products

            // 1st IAP Product (Consumable) ------------------------------------
            let firstProduct = response.products[0] as SKProduct

            // Get its price from iTunes Connect
            let numberFormatter = NumberFormatter()
            numberFormatter.formatterBehavior = .behavior10_4
            numberFormatter.numberStyle = .currency
            numberFormatter.locale = firstProduct.priceLocale
            let price1Str = numberFormatter.string(from: firstProduct.price)

            // Show its description
            //consumableLabel.text = firstProduct.localizedDescription + "\nfor just \(price1Str!)"
            // ------------------------------------------------



            // 2nd IAP Product (Non-Consumable) ------------------------------
            let secondProd = response.products[0] as SKProduct

            // Get its price from iTunes Connect
            numberFormatter.locale = secondProd.priceLocale
            let price2Str = numberFormatter.string(from: secondProd.price)

            // Show its description
            //nonConsumableLabel.text = secondProd.localizedDescription + "\nfor just \(price2Str!)"
            // ------------------------------------
        }
    }

    func canMakePurchases() -> Bool {  return SKPaymentQueue.canMakePayments()  }
    func purchaseMyProduct(product: SKProduct) {
        if self.canMakePurchases() {
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(self)
            SKPaymentQueue.default().add(payment)

            print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
            productID = product.productIdentifier


            // IAP Purchases dsabled on the Device
        } else {
            UIAlertView(title: "IAP Tutorial",
                        message: "Purchases are disabled in your device!",
                        delegate: nil, cancelButtonTitle: "OK").show()
        }
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction:AnyObject in transactions {
            if let trans = transaction as? SKPaymentTransaction {
                switch trans.transactionState {

                case .purchased:
                    SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)

                    // The Consumable product (10 coins) has been purchased -> gain 10 extra coins!
                    if productID == PREMIUM_PRODUCT_ID {

                        // Save your purchase locally (needed only for Non-Consumable IAP)
                        nonConsumablePurchaseMade = true
                        UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")

                        //premiumLabel.text = "Premium version PURCHASED!"

                        UIAlertView(title: "IAP Tutorial",
                                    message: "You've successfully unlocked the Premium version!",
                                    delegate: nil,
                                    cancelButtonTitle: "OK").show()
                    }

                    break

                case .failed:
                    SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
                    break
                case .restored:
                    SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
                    break

                default: break
                }}}
    }

}

1 个答案:

答案 0 :(得分:0)

你的代码太长了,所以我冒昧地猜测了相关内容:

import UIKit
import StoreKit

class Settings: UIViewController, SKProductsRequestDelegate,
SKPaymentTransactionObserver {

    var iapProducts = [SKProduct]()

    @IBAction func removeAds(_ sender: Any) {
        purchaseMyProduct(product: iapProducts[0])

    }
}

当您声明iapProducts时,您正在创建一个不包含值的空数组。

然后,在您的removeAds函数中,您告诉它对第一个元素执行某些操作。

我会猜测一无所有,所以你强迫它访问一个不存在的对象。

尝试以下操作,看看它是否解决了您的问题。

var iapProducts: [SKProduct]?

@IBAction func removeAds(_ sender: Any) {
    guard let product = iapProducts?.first else { return }

    purchaseMyProduct(product: product)
}

这完成了两件事:

  1. 它使您的[SKProduct]数组成为可选
  2. 守卫声明安全地展开第一个产品,所以只有当一个产品存在时,它才会尝试调用你的purchaseMyProduct功能。否则,它就会退出