Swift/Xcode 9 - 应用内购买 - 在展开可选值时意外发现 nil

Posted

技术标签:

【中文标题】Swift/Xcode 9 - 应用内购买 - 在展开可选值时意外发现 nil【英文标题】:Swift/Xcode 9 - In App Purchases - unexpectedly found nil while unwrapping an Optional value 【发布时间】:2017-09-28 11:17:41 【问题描述】:

我在从我的应用中删除广告时遇到了一些困难。

问题是当我单击删除广告按钮时,应用程序崩溃并显示消息fatal error: unexpectedly found nil while unwrapping an Optional value

我在网上看过,但是,它们似乎已经过时了。

我查看了我的控制台,我可能发现了错误product = (SKProduct)nil

有趣的是,我之前曾实施过一次这种方法,但遇到了同样的问题,结果出乎意料地奏效了。所以我只是重新使用了代码并更改了productID

我认为实际注册应用内购买的 ID 可能需要时间。但是,我已经意识到同样的问题。有人可以帮助我并告诉我可能是什么问题吗?

点击删除广告按钮后,我的游戏崩溃了。我的删除按钮的操作/方法是removeAds_TouchUpInside

import UIKit
import SpriteKit
import GameplayKit
import GoogleMobileAds
import StoreKit

class GameViewController: UIViewController, GADInterstitialDelegate, SKPaymentTransactionObserver, SKProductsRequestDelegate 
    var fullScreenAds : GADInterstitial!
    @IBOutlet weak var removeAdsButton: UIButton!

    var product: SKProduct?
    var productID = "com.USER.GAME.removeAds"

    override func viewDidLoad() 
       super.viewDidLoad()

        let save = UserDefaults.standard
        if save.value(forKey: "Purchase") == nil  
            let request = GADRequest()
            request.testDevices = [kGADSimulatorID]
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: "loadAds"), object: nil)

         else 
        
              if let view = self.view as! SKView? 
            if let scene = SKScene(fileNamed: "GameMenuScene") 
                scene.scaleMode = .aspectFill
                view.presentScene(scene)
                
            view.ignoresSiblingOrder = true
            view.showsFPS = false
            view.showsNodeCount = false
        
    

    override func viewDidAppear(_ animated: Bool) 
      super.viewDidAppear(animated)
    

    @IBAction func removeAds_TouchUpInside(_ sender: Any) 
        let payment = SKPayment(product: product!)
        SKPaymentQueue.default().add(payment)
    

    override func viewWillLayoutSubviews() 
        NotificationCenter.default.addObserver(self, selector: #selector(self.loadAds), name: NSNotification.Name(rawValue: "loadAds"), object: nil)
    
    func loadAds() 
        self.fullScreenAds = createAndLoadInterstitials()

    
    override var shouldAutorotate: Bool 
        return true
    

    override var supportedInterfaceOrientations: UIInterfaceOrientationMask 
        if UIDevice.current.userInterfaceIdiom == .phone 
            return .allButUpsideDown
         else 
            return .all
        
    

    override var prefersStatusBarHidden: Bool 
        return true
    

    func createAndLoadInterstitials() -> GADInterstitial? 
        fullScreenAds = GADInterstitial(adUnitID: "ca-app-pub-7212561254132738/9424537183")
        guard let fullScreenAds = fullScreenAds else 
            return nil
        

        let request = GADRequest()
        request.testDevices = [kGADSimulatorID]
        fullScreenAds.load(request)
        fullScreenAds.delegate = self

        return fullScreenAds
    

    func interstitialDidReceiveAd(_ ad: GADInterstitial) 
        print("Ad received")
        ad.present(fromRootViewController: self)
    

    func interstitialDidFail(toPresentScreen ad: GADInterstitial) 
        print("No ad can be loaded")

    

    func getPurchaseInfo() 
        if SKPaymentQueue.canMakePayments() 
            let request = SKProductsRequest(productIdentifiers: NSSet(objects: self.productID) as! Set<String>)
            request.delegate = self
            request.start()
         else 
            print("Enable in app purchase!")
            return
        
    

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) 
        var products = response.products

        if (products.count == 0) 
            print("Error")
            return
         else 
            product = products[0]
            removeAdsButton.isEnabled = true
            print("Succes!")
        

        let invalids = response.invalidProductIdentifiers

        for product in invalids 
            print("Product not found \(product)")
        
    
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) 
        for transaction in transactions 
            switch transaction.transactionState 
            case SKPaymentTransactionState.purchased:
                SKPaymentQueue.default().finishTransaction(transaction)
                print("SuccessPayementQeue!")
                removeAdsButton.isEnabled = false
                let save = UserDefaults.standard
                save.set(true, forKey: "Purchase")
                save.synchronize()

            case SKPaymentTransactionState.failed:
                SKPaymentQueue.default().finishTransaction(transaction)
                print("Failed transaction state")
            default:
                break
            
        
    

【问题讨论】:

What does "fatal error: unexpectedly found nil while unwrapping an Optional value" mean?的可能重复 @Shades 我知道什么是致命错误,您必须先使用guardif let 解开该值,但这是应用内购买。所以我是个大笨蛋。希望这可以澄清一切。 :) 【参考方案1】:

您的产品nil,因此您面临问题,因此您可以编写如下代码来解决它。

@IBAction func removeAds_TouchUpInside(_ sender: Any) 
        if let myP = product 
           let payment = SKPayment(product: myP)
           SKPaymentQueue.default().add(payment)
        
        else 
            print("Product is not found.")
        

【讨论】:

似乎所做的就是打印Product is not found. 是的,所以您应该看看为什么找不到您的产品?表示检查 product_id 是否正确? 我的产品 id 是正确的,我之前遇到过这个问题,突然它开始工作了。

以上是关于Swift/Xcode 9 - 应用内购买 - 在展开可选值时意外发现 nil的主要内容,如果未能解决你的问题,请参考以下文章

如果 UIButton 被选中,在 Swift (Xcode 9) 中取消选择另一个 UIButton

Swift Xcode 9.4 框架

Xcode 9 在每周限制之前停止签名方式

iOS:在应用内购买中上传托管内容时出现问题 (ITMS-4200)

我们可以在应用内购买中提供“优惠”吗?

如何使用 Swift 2 + XCode 7 + iOS 9 获取和解析 JSON [重复]