Barry Nailor
Barry Nailor

Reputation: 417

EXC_BAD_ACCESS during in app purchase test

Running a test for my in app purchase (first time doing in app purchases). I get EXC_BAD_ACCESS on the third line of this code:

    SKPayment *payment = [SKPayment paymentWithProduct:electronicProd];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

The is under an IBAction for a button. electronicPack is declared in the header as a SKProduct. Threw some NSLogs in the productsRequest didReceiveResponse, and when the product was requested (in the viewDidLoad) and they showed it was correctly fetching the product and storing it in electronicPack. Defined electronicPack as [[request.products] objectAtIndex:0] in the didReceiveResponse page. So yea. Thats where im at, dont know what to do. Any help is appreciated.

UPDATE: FIXED accidentally left in code that was adding an extra transaction observer lol

Upvotes: 23

Views: 5732

Answers (7)

Skoua
Skoua

Reputation: 3603

If you're creating a dedicated class for SKPaymentTransactionObserver don't forget that it must be retained.

I got the error before realizing this, here's an example in AppDelegate:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    var myTransactionObserver: MyTransactionObserver!


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {

        // don't
        let myTransactionObserver = MyTransactionObserver()

        // do
        myTransactionObserver = MyTransactionObserver()

        SKPaymentQueue.default().add(myTransactionObserver)

        return true
    }

    // ...
}

Upvotes: 1

Usman Nisar
Usman Nisar

Reputation: 3081

I Have the same issue, my solution was to call [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

on store observer transaction finish/failed/completed callbacks

Upvotes: 0

imike
imike

Reputation: 5656

Mr.T answer is the best solution!

In swift I call this removeTransactionObserver here:

deinit {
    SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
}

Upvotes: 12

Shayno
Shayno

Reputation: 808

I had the same error, quite simple to solve really. In my header file I had a SKProduct declared:

@property SKProduct *product;

I just changed it to:

@property (retain) SKProduct *product;

and it all works fine. Hope this helps someone.

Upvotes: 2

Zorayr
Zorayr

Reputation: 24902

Seems like the issue is from trying to add a transaction observer before removing the previous one. Add the following to your controller to fix this issue:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}

Hope this helps!

Upvotes: 27

Mr. T
Mr. T

Reputation: 754

I've had the same issue, my solution was to call

[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

on leaving the In-App Store in my App. Maybe it will help someone in the future.

Upvotes: 41

andreamazz
andreamazz

Reputation: 4286

You need to retain the object that you are creating

- (void)viewDidLoad {
   //... stuff
   SKProduct* electronicProduct = //...
   [electronicProduct retain];
   //... otherstuff
}

viewDidLoad is wrapped by the system in a autorelease pool, paymentWithProduct: returns an autorelease object. When viewDidLoad is done, all autorelease object are released, that's why you get a bad memory access when you try to access to it later.

Upvotes: 10

Related Questions