Unbundling with In App Purchase (IAP) Swift

1

I'm trying to use the In App Purchase to remove ads from my app, but the ads are located in a View other than where the IAP code is. I think I'm removing it in a non-efficient or wrong way, because the code is breaking in the remove function:

func removeallAds() {
    ViewController().bannerAd.removeFromSuperview()
}

This is showing me the following error:

Fatal error: unexpectedly found nil while unwrapping an optional value (lldb)

This is my View from my IAP:

import UIKit
import StoreKit

class IapViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {

    @IBOutlet weak var removeAds: UIButton!
    @IBOutlet weak var restorePurchase: UIButton!


    @IBAction func removeAdsAct(sender: AnyObject) {
        for product in list{
            var prodId = product.productIdentifier
            if (prodId == "com.hazeApps.removeAds"){
                p = product
                buyProduct()
                break;
            }

        }
    }


    @IBAction func resPurchaseAct(sender: AnyObject) {
        SKPaymentQueue.defaultQueue().addTransactionObserver(self)
        SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        removeAds.enabled = false


        //IAP Setup
        if(SKPaymentQueue.canMakePayments()){
            println("IAP is up and running")
            var productId: NSSet = NSSet(object: "com.hazeApps.removeAds")
            var request: SKProductsRequest = SKProductsRequest(productIdentifiers: productId)
            request.delegate = self
            request.start()
        } else {
            println("enable IAPs")
        }


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    var list = [SKProduct]()
    var p = SKProduct()

    func buyProduct(){
        println("buy " + p.productIdentifier)
        var pay = SKPayment(product: p)
        SKPaymentQueue.defaultQueue().addTransactionObserver(self)

            SKPaymentQueue.defaultQueue().addPayment(pay as SKPayment)
    }

    func removeallAds() {
        ViewController().bannerAd.removeFromSuperview()
    }


    func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
        println("Product Request")
        var myProducts = response.products

        for product in myProducts{
            println("product added")
            println(product.productIdentifier)
            println(product.localizedTitle)
            println(product.localizedDescription)
            println(product.price)

            list.append(product as SKProduct)
        }

        removeAds.enabled = true
    }

    func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue!) {
        println("Transaction restored")
        var purchasedItemIDS = []
        for transaction in queue.transactions{
            var t: SKPaymentTransaction = transaction as SKPaymentTransaction

            let prodId = t.payment.productIdentifier as String

            switch prodId{
            case "com.hazeApps.removeAds":
                println("Remove Adds")
                removeallAds()
            default:
                println("IAP not setup")

            }
        }
    }

    func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {

        println("add payment")

        for transaction: AnyObject in transactions{
            var trans = transaction as SKPaymentTransaction
            println(trans.error)

            switch trans.transactionState{

            case .Purchased:
                println("Unlock IAP here")
                println(p.productIdentifier)

                let productId = p.productIdentifier as String
                switch productId{
                    case "com.hazeApps.removeAds":
                        println("Remove Adds")
                        removeallAds()
                    default:
                        println("IAP not setup")

                }
                queue.finishTransaction(trans)
                break;

            case .Failed:
                println("buy error")
                queue.finishTransaction(trans)
                break;

            default:
                println("Default")
                break;


            }
        }
    }

    func finishTransaction(trans: SKPaymentTransaction){
        println("Finish Trans")
    }

    func paymentQueue(queue: SKPaymentQueue!, removedTransactions transactions: [AnyObject]!) {
        println("Removed Trans")
    }

}

    

asked by anonymous 21.01.2015 / 21:13

1 answer

1

The problem is that when ViewController() is called it creates a new instance of class ViewController and when you attempt to access bannerAd the program wraps because bannerAd is nil .

In order to access the attributes in the current instance of ViewController you need to pass some reference to the IapViewController class.

You can do this:

  • Declare a variable in your class IapViewController to save the current instance of ViewController

    // IapViewController
    var mainVC: ViewController!
    ...
    func removeallAds() {
       // se bannerAd for nil, removeFromSuperview() nem vai chegar a ser chamado
       mainVC.bannerAd?.removeFromSuperview()
    }
    
  • Name the following that calls IapViewController (I'll use "iapVcSegue") and add this in prepareForSegue of class ViewController :

    // prepareForSegue de ViewController
    if segue.identifier == "iapVcSegue" {
        var vc = segue.destinationViewController as IapViewController
        vc.mainVC = self;
    }
    
  • This technique works but it may not be the best mode. As the ad is going to be permanently removed I think it would be more interesting if you use NSUserDefaults or add a global configuration singleton and the viewDidLoad/viewWillAppear of ViewController check and remove / do not display the banner.     

    21.01.2015 / 23:07