Minus In App Purchase (IAP) Swift Ad

Asked

Viewed 148 times

1

I’m trying to use In App Purchase to remove ads from my app, but the ads are located in a different view than where the IAP code is. I think I’m removing in an inefficient or wrong way, because the code is breaking in the remove function:

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

This showing me the following error:

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

This is my view of 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")
    }

}

Other Thing, I have some line of code that Handle in case of wireless Connections to make the bannerAd Hide, If the Ad is Removed from Superview it Might get some error in this Lines?

  • Have you checked whether bannerAd is not nil at this time?

  • If it’s because I’m importing wrong, because it wasn’t meant to be

  • Where it comes from bannerAd?

  • From Viewcontroller, but I’m calling him at Iadviewcontroller

  • How you are instantiating IadViewController? Storyboard?

  • Yes, it’s a View Controller like any other

Show 1 more comment

1 answer

1

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

To be able to access attributes in the current instance of ViewController you need to pass some reference to the class IapViewController.

You can do it like this:

  1. 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()
    }
    
  2. Give a name to the following who calls the IapViewController (I will use "iapVcSegue") and add this to prepareForSegue class ViewController:

    // prepareForSegue de ViewController
    if segue.identifier == "iapVcSegue" {
        var vc = segue.destinationViewController as IapViewController
        vc.mainVC = self;
    }
    

This technique works but may not be the best way. As the ad will be permanently removed I think it would be more interesting you use NSUserDefaults or add a global configuration Singleton and viewDidLoad/viewWillAppear of ViewController check and remove/not show the banner.

  • Ta speaking that Viewcontroller? does not have a member called bannerAd

  • @Skal I asked you before where it came from bannerAd and you said "Viewcontroller". Where does it come from, then?

  • Comes from the controller view yes class ViewController: UIViewController, CLLocationManagerDelegate, UITextFieldDelegate, ADBannerViewDelegate {
 
 //Definindo View Varaibles
 
 
 @IBOutlet weak internal var bannerAd: ADBannerView!

  • So that’s it. You can try this solution that will work for you.

  • I tried, but I get two errors in Viewcontroller: Use of undeclared type Newviewcontroller. And in Iapviewcontroller: Viewcontroller? does not have a member called bannerAd

  • Exchange for Iapviewcontrler. I copied from the test I made and forgot to change. I edited the answer.

  • In Iapviewcontroller still gives error: Viewcontroller? does not have a member called bannerAd

  • Probably because the member is declared as International. You can take out the Internal or create a method in the Viewcontroller class that removes the element and call it Iapviewcontroller the same way.

  • I took out the interstate, same mistake.

  • Try to change var mainVC: ViewController? for var mainVC: ViewController!.

  • Ok, now the error is gone, but it’s still showing up: Fatal error: unexpectedly found nil while unwrapping an Optional value (lldb)

  • Put a breakpoint in the prepareForSerge and make sure mainVC is set correctly.

  • Yes this set correctly

Show 8 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.