2017-01-27 9 views
-2

私はアプリ内購入を取り入れようとしています。なんらかの理由で、私は致命的なエラーが発生しています。「致命的なエラー:インデックスが範囲外です」というのは、SKProduct製品を保持する配列です。私はアプリの購入で1つを消費することはありませんが、後で追加することを決定するかもしれません。私は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 
       }}} 
    } 

} 
+0

このエラーは、配列の存在しない要素(たとえば、3番目の項目の配列の4番目の項目)にアクセスしようとしていることを意味します。どのラインでエラーが発生しますか? – Coder256

+0

あなたの質問は2通りの方法で編集してください。 (1)あなたの問題に関連していないコードを削除してください。私たちは本当にこのコードをすべて網羅できません。 (2)エラーを与えるコード行を正確に指してください。 BONUS:あなたのコードにブレークポイントを設定しましたか?どの配列がどこにあるのかわかるかもしれませんが、何が問題なのでしょうか?内容はエラーが発生したときですか? – dfd

+0

ok私はそれを更新します –

答えて

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) 
} 

これは2つのことを達成:

  1. それはあなたの
  2. [SKProduct]配列オプションのガード文は安全に1が存在する場合にのみ、それはあなたの purchaseMyProductを呼び出そうとしますので、最初の製品をアンラップます関数。それ以外の場合、終了します。
関連する問題