I implemented app purchases into my store scene for my game, and I had problems moving from the store scene to another scene. This seems to be a game crash and gives me this error.
Thread 1: EXC_BAD_ACCESS (code=1, address=0x840f8010)
Or it gives me several versions of other errors, such as:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x3f8)
it also sometimes gives me an error that changes lines in a subclass, for example:

When I comment on the code in a subclass that searches for information about buying an application or puts the phone in airplane mode, it works fine and the problem goes away.
I have a SKnode subclass that retrieves information about purchased items and then displays it using SKLabels and sprite nodes to display an image of a purchase in a store, as shown below:
class InAppPurchaseItems: SKNode, SKProductsRequestDelegate { var shopItemNode = SKSpriteNode() var itemPriceBackground = SKSpriteNode() var shopItemLabel = SKLabelNode() var shopItemTitleLabel = SKLabelNode() var pressableNode = SKSpriteNode() var itemPriceLabel = SKLabelNode() var title: String = "" var information: String = "" var image: String = "" var price:String = "X" func createAppPurchaseItem(ID: String, purchaseImage: String, purchaseTitle:String) { title = purchaseTitle image = purchaseImage createTheNode() //let product = SKProduct() let productID: NSSet = NSSet(objects: ID) //"RedShield.Astrum.Purchase", "DoubleCoin.Astrum.Purchase") let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>) request.delegate = self as? SKProductsRequestDelegate request.start() } public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { print("product request...") let myProduct = response.products for product in myProduct { print("product added") if product.productIdentifier == "RedShield.Astrum.Purchase" { price = priceStringForProduct(item: product)! information = product.localizedDescription } else if product.productIdentifier == "DoubleCoin.Astrum.Purchase" { price = priceStringForProduct(item: product)! information = product.localizedDescription } else if product.productIdentifier == "1500Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirOne") } else if product.productIdentifier == "7500Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirTwo") } else if product.productIdentifier == "14000Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirThree") } else if product.productIdentifier == "28000Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirFour") } else if product.productIdentifier == "65000Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirFive") } else if product.productIdentifier == "128000Stars.Astrum.Purchase" { price = priceStringForProduct(item: product)! shopItemNode.texture = SKTexture(imageNamed: "BuyStarsTeirSix") } createShopLabels() } } func priceStringForProduct(item: SKProduct) -> String? { let price = item.price if price == 0 { return "GET" //or whatever you like } else { let numberFormatter = NumberFormatter() let locale = item.priceLocale numberFormatter.numberStyle = .currency numberFormatter.locale = locale return numberFormatter.string(from: price) } } func createTheNode() { let tex:SKTexture = SKTexture(imageNamed: image) shopItemNode = SKSpriteNode(texture: tex, color: SKColor.black, size: CGSize(width: 85, height: 85)) //frame.maxX / 20, height: frame.maxY / 20)) shopItemNode.zPosition = -10 shopItemNode.position = CGPoint(x: 0, y: 35) self.addChild(shopItemNode) self.name = "ShopItem" self.zPosition = -11 shopItemTitleLabel = SKLabelNode(fontNamed: "Avenir-Black") shopItemTitleLabel.fontColor = UIColor.black; shopItemTitleLabel.fontSize = 15 //self.frame.maxY/30 shopItemTitleLabel.position = CGPoint (x: 0, y: -30) shopItemTitleLabel.text = "\(title)" shopItemTitleLabel.zPosition = -9 self.addChild(shopItemTitleLabel) itemPriceBackground = SKSpriteNode(texture: SKTexture(imageNamed: "PriceShopBackground"), color: .clear, size: CGSize(width: 80, height: 30)) //SKSpriteNode(color: SKColor.black, size: CGSize(width: 65, height: 20)) //itemPriceBackground.alpha = 0.4 itemPriceBackground.zPosition = -10 itemPriceBackground.position = CGPoint(x: 0, y: -54) addChild(itemPriceBackground) pressableNode = SKSpriteNode(texture: nil, color: .clear, size: CGSize(width: 100, height: 140)) pressableNode.zPosition = -7 pressableNode.position = CGPoint(x: 0, y: 0) shopItemSprites.append(pressableNode) addChild(pressableNode) } func createShopLabels() { shopItemLabel = SKLabelNode(fontNamed: "Avenir-Black") shopItemLabel.fontColor = UIColor.white; shopItemLabel.fontSize = 15 //self.frame.maxY/30 shopItemLabel.position = CGPoint (x: 0, y: -60) shopItemLabel.text = "\(price)" shopItemLabel.zPosition = -9 addChild(shopItemLabel) } }
they are then displayed on the store scene using the following code:
let ShopItem = InAppPurchaseItems() ShopItem.createAppPurchaseItem(ID: "DoubleCoin.Astrum.Purchase", purchaseImage: "2StarCoin", purchaseTitle: "+2 In Game Pickups") ShopItem.position = CGPoint(x: self.frame.midX / 1.6, y: self.frame.midY * 0.8) ShopItem.zPosition = 100 ShopItem.name = "Shp0" moveableArea.addChild(ShopItem)
The main class of the store
The main class of stores also has an application purchase code, which is used to purchase a product, as well as to search for product information, as in a subclass, as shown below.
class ShopItemMenu: SKScene, SKProductsRequestDelegate, SKPaymentTransactionObserver { //Purchase Variables var listOfProducts = [SKProduct]() var p = SKProduct() override func didMoveToView(to view: SKView) { let ShopItem = InAppPurchaseItems() ShopItem.createAppPurchaseItem(ID: "DoubleCoin.Astrum.Purchase", purchaseImage: "2StarCoin", purchaseTitle: "+2 In Game Pickups") ShopItem.position = CGPoint(x: self.frame.midX / 1.6, y: self.frame.midY * 0.8) ShopItem.zPosition = 100 ShopItem.name = "Shp0" moveableArea.addChild(ShopItem) } //This function allows for a product to be bought buy the user and starts the proccess for purchasing func appPurchaseBuying(appPurchaseID:String) { for product in listOfProducts { let prodID = product.productIdentifier if(prodID == appPurchaseID) { p = product buyProduct() } } } //This Function restores all previously purchased Items (use this for the restor button. func restorePurchasesOfItems() { SKPaymentQueue.default().add(self) SKPaymentQueue.default().restoreCompletedTransactions() } //This function checks if they can make payments and then loads the product ids from a harcoded set. (use this to start when the scene starts) func checkCanMakePayment() { if (SKPaymentQueue.canMakePayments()) { print("can make payments...") let productID: NSSet = NSSet(objects: "RedShield.Astrum.Purchase", "DoubleCoin.Astrum.Purchase") let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>) request.delegate = self request.start() } else { let alert = UIAlertController(title: "In-App Purchases Not Enabled", message: "Please enable In App Purchases in Settings", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "Settings", style: UIAlertActionStyle.default, handler: { alertAction in alert.dismiss(animated: true, completion: nil) let url: NSURL? = NSURL(string: UIApplicationOpenSettingsURLString) if url != nil { UIApplication.shared.openURL(url! as URL) } })) alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { alertAction in alert.dismiss(animated: true, completion: nil) })) if let vc = self.scene?.view?.window?.rootViewController { vc.present(alert, animated: true, completion: nil) } } } //This allows the user to buy the product with a product idetifier given by the variable "p" func buyProduct() { print("buying " + p.productIdentifier) let pay = SKPayment(product: p) SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(pay as SKPayment) } //This Function gets all the avaliable products from apple and puts them into the product Array called listOfProducts public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { /* print("product request...") let myProduct = response.products for product in myProduct { print("product added") if product.productIdentifier == "RedShield.Astrum.Purchase" { shieldPurchasePrice = priceStringForProduct(item: product)! } else if product.productIdentifier == "DoubleCoin.Astrum.Purchase" { DoubleCoinPurchasePrice = priceStringForProduct(item: product)! } /*print(product.productIdentifier) print(product.localizedTitle) print(product.localizedDescription) print(product.price) */ listOfProducts.append(product) }*/ } func priceStringForProduct(item: SKProduct) -> String? { let price = item.price if price == 0 { return "GET" //or whatever you like } else { let numberFormatter = NumberFormatter() let locale = item.priceLocale numberFormatter.numberStyle = .currency numberFormatter.locale = locale return numberFormatter.string(from: price) } } //This Function restores all the already purchased products so that things can be restored such as shield public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { print("restoring all...") for transaction in queue.transactions { let t: SKPaymentTransaction = transaction let prodID = t.payment.productIdentifier as String switch prodID { case "RedShield.Astrum.Purchase": isRedShieldPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isRedShieldPurchaseOn, forKey: "shieldPurchase") print("finished restoring this purchase") case "DoubleCoin.Astrum.Purchase": isCoinPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isCoinPurchaseOn, forKey: "doubleCoinPurchase") print("finished restoring this purchase") default: print("IAP not found") } } alert(title: "Restored", msg: "Purchases were restored") } //This Function is run when the user makes a purchase and checks the state of the purchase to make sure it works public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { print("adding payment...") for transaction: AnyObject in transactions { let trans = transaction as! SKPaymentTransaction print(trans.error) switch trans.transactionState { case .purchased: print("buying ok, Unlocking purchase...") print(p.productIdentifier) let prodID = p.productIdentifier switch prodID { case "RedShield.Astrum.Purchase": isRedShieldPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isRedShieldPurchaseOn, forKey: "shieldPurchase") print("unlocked Purchase") case "DoubleCoin.Astrum.Purchase": isCoinPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isCoinPurchaseOn, forKey: "doubleCoinPurchase") print("unlocked Purchase") case "SOME IN APP PURCHASE ID HERE": print("unlocked Purchase") default: print("IAP Not found") } queue.finishTransaction(trans) case .failed: print("error with payment...") queue.finishTransaction(trans) default: print("Default") } } }
Am I going to do it right, or is there a better way to do this, and how can I fix the error I have?
EDIT

EDIT 2

EDIT 3

EDIT 4
import Foundation import SpriteKit import StoreKit class PurchaseService { static let session = PurchaseService() var products = [SKProduct]() var p = SKProduct() //This function allows for a product to be bought buy the user and starts the proccess for purchasing func appPurchaseBuying(appPurchaseID:String) { for product in products { let prodID = product.productIdentifier if(prodID == appPurchaseID) { p = product buyProduct() } } } //This Function restores all previously purchased Items (use this for the restor button. func restorePurchasesOfItems() { //SKPaymentQueue.default().add(self) SKPaymentQueue.default().restoreCompletedTransactions() } //This function checks if they can make payments and then loads the product ids from a harcoded set. (use this to start when the scene starts) func checkCanMakePayment() { if (SKPaymentQueue.canMakePayments()) { print("can make payments...") let productID: NSSet = NSSet(objects: "RedShield.Astrum.Purchase", "DoubleCoin.Astrum.Purchase") let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>) //request.delegate = self request.start() } else { let alert = UIAlertController(title: "In-App Purchases Not Enabled", message: "Please enable In App Purchases in Settings", preferredStyle: UIAlertControllerStyle.alert) alert.addAction(UIAlertAction(title: "Settings", style: UIAlertActionStyle.default, handler: { alertAction in alert.dismiss(animated: true, completion: nil) let url: NSURL? = NSURL(string: UIApplicationOpenSettingsURLString) if url != nil { UIApplication.shared.openURL(url! as URL) } })) alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: { alertAction in alert.dismiss(animated: true, completion: nil) })) } } //This allows the user to buy the product with a product idetifier given by the variable "p" func buyProduct() { print("buying " + p.productIdentifier) let pay = SKPayment(product: p) //SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(pay as SKPayment) } //This Function gets all the avaliable products from apple and puts them into the product Array called listOfProducts public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { print("product request...") let myProduct = response.products for product in myProduct { print("product added") products.append(product) } } func priceStringForProduct(item: SKProduct) -> String? { let price = item.price if price == 0 { return "GET" //or whatever you like } else { let numberFormatter = NumberFormatter() let locale = item.priceLocale numberFormatter.numberStyle = .currency numberFormatter.locale = locale return numberFormatter.string(from: price) } } //This Function restores all the already purchased products so that things can be restored such as shield public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) { print("restoring all...") for transaction in queue.transactions { let t: SKPaymentTransaction = transaction let prodID = t.payment.productIdentifier as String switch prodID { case "RedShield.Astrum.Purchase": isRedShieldPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isRedShieldPurchaseOn, forKey: "shieldPurchase") print("finished restoring this purchase") case "DoubleCoin.Astrum.Purchase": isCoinPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isCoinPurchaseOn, forKey: "doubleCoinPurchase") print("finished restoring this purchase") default: print("IAP not found") } } //alert(title: "Restored", msg: "Purchases were restored") } //This Function is run when the user makes a purchase and checks the state of the purchase to make sure it works public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { print("adding payment...") for transaction: AnyObject in transactions { let trans = transaction as! SKPaymentTransaction print(trans.error) switch trans.transactionState { case .purchased: print("buying ok, Unlocking purchase...") print(p.productIdentifier) let prodID = p.productIdentifier switch prodID { case "RedShield.Astrum.Purchase": isRedShieldPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isRedShieldPurchaseOn, forKey: "shieldPurchase") print("unlocked Purchase") case "DoubleCoin.Astrum.Purchase": isCoinPurchaseOn = true let defaults = UserDefaults.standard defaults.set(isCoinPurchaseOn, forKey: "doubleCoinPurchase") print("unlocked Purchase") case "SOME IN APP PURCHASE ID HERE": print("unlocked Purchase") default: print("IAP Not found") } queue.finishTransaction(trans) case .failed: print("error with payment...") queue.finishTransaction(trans) default: print("Default") } } } }