0

Good afternoon al

Obs: I use the Rechibility class to check if the user internet is connected or not but in this case the class verify the internet but i dont receive the information from apple. Just in this case

I created a payment system and it works fine, however there is a case that it is crashing which is:

1: User enters app without internet connection (Wi-Fi or 4G) 2: User tries to buy the app offline and gets into the purchase viewcontroller 3: Press the iphone HOME button and then connect the Wi-Fi or 4G 4: After return to the app and press the button to purchase again and the crash appear

This only happens in this situation, in the other test cases I did not receive any errors.

I can not see why this error occurred.

Below is my code and images about the error.

My current code:

import UIKit
import StoreKit

protocol IAPManagerDelegate 
{
    func managerDidRestorePurchases()
}

class IAPManager: NSObject, SKProductsRequestDelegate,     SKPaymentTransactionObserver, SKRequestDelegate 
{

static let sharedInstance = IAPManager()

var request:SKProductsRequest!
var products:NSArray!

//Load product identifiers for store usage
func setupInAppPurchases()
{
    self.validateProductIdentifiers(self.getProductIdentifiersFromMainBundle())

    SKPaymentQueue.default().add(self)
}

//Get product identifiers
func getProductIdentifiersFromMainBundle() -> NSArray 
{
    var identifiers = NSArray()
    if let url = Bundle.main.url(forResource: "iap_product_ids", withExtension: "plist")
    {
        identifiers = NSArray(contentsOf: url)!
    }

    return identifiers
}

//Retrieve product information
func validateProductIdentifiers(_ identifiers:NSArray) 
{

    if Reachability.isConnectedToNetwork() == true
    {
        print("Enter")
        let productIdentifiers = NSSet(array: identifiers as [AnyObject])
        let productRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
        self.request = productRequest
        productRequest.delegate = self
        productRequest.start()
    }

}

func createPaymentRequestForProduct(_ product:SKProduct)
{

    if Reachability.isConnectedToNetwork() == true
    {
        let payment = SKMutablePayment(product: product)
        payment.quantity = 1
        SKPaymentQueue.default().add(payment)
    }
}


//MARK: SKProductsRequestDelegate 
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) 
{
    //
    self.products = response.products as NSArray!

    for product in products
    {
        let temp = product as! SKProduct

        if temp.productIdentifier == "monthly.subscription"
        {
            print("price: \(temp.price)")
            formatProductMonth(free: temp)
        }
        if temp.productIdentifier == "weekly.subscription"
        {
            print("price: \(temp.price)")
            formatProductFree(free: temp)
        }
        if temp.productIdentifier == "yearly.subscription"
        {
            print("price: \(temp.price)")
            formatProductYear(free: temp)
        }
    }
    // print("Product[0]: \(string)")
    // print("Product[1]: \(prod1.productIdentifier)")
    // print("Product[2]: \(prod2.productIdentifier)")
}

//MARK: SKPaymentTransactionObserver Delegate Protocol
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) 
{


    //
    for transaction in transactions as [SKPaymentTransaction]
    {
        switch transaction.transactionState
        {
            case .purchasing:
            print("Purchasing")
            UIApplication.shared.isNetworkActivityIndicatorVisible = true
            break
            case .deferred:
            print("Deferrred")

            let alertController: UIAlertController = UIAlertController(title: "Deferred", message: "Purchase deferred", preferredStyle: .alert)
            let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
            alertController.addAction(dismiss)
            alertController.show()
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
            break
            case .failed:
            print("Failed")
            //print(transaction.error?.localizedDescription)
            UIApplication.shared.isNetworkActivityIndicatorVisible = false
            SKPaymentQueue.default().finishTransaction(transaction)
            let alertController: UIAlertController = UIAlertController(title: "Failed", message: "Purchase failed", preferredStyle: .alert)
            let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
            alertController.addAction(dismiss)
            alertController.show()
            //UIApplication.shared.keyWindow?.rootViewController?.present(alertController, animated: true, completion: nil)
            break
            case.purchased:
            StopActivator()
            print("Purchased")
            self.verifyReceipt(transaction)
            let thankyou = UserDefaults.standard.bool(forKey: "Purchased")

            if thankyou == true
            {

                let alertController: UIAlertController = UIAlertController(title: "Thank You", message: "Purchase completed", preferredStyle: .alert)
                let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: { (action: UIAlertAction!) in
                UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)
                })
                alertController.addAction(dismiss)
                alertController.show()

            }

            break
            case .restored:
            print("Restored")
            let alertController: UIAlertController = UIAlertController(title: "Restore Success", message: "Your purchases have been restored", preferredStyle: .alert)
            let dismiss = UIAlertAction(title: "OK", style: UIAlertActionStyle.cancel, handler: nil)
            alertController.addAction(dismiss)
            alertController.show()
            break

        }
    }
}

Pictures for the errors above:

First Image

Second Image

Vinodh
  • 5,262
  • 4
  • 38
  • 68
Yuri Jose
  • 21
  • 1
  • 4

1 Answers1

0

The "Unexpectedly found nil" error happens when you try to access something that doesn't exist. So on the line you gave, it'd be the IAPManager.sharedInstance.products?.object(at: 0).

It would be worth tracking this, and finding out why it is empty (I presume it should have a value if you are trying to access it).

Danny Wilson
  • 331
  • 2
  • 11
  • Yep Danny i know about this but is very weird because the user offline dont get receive the information so i use the class Rechiabilty to check if the internet is connected but when i check the info about the products dont return – Yuri Jose Nov 20 '16 at 20:37