- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我已经在我的游戏的商店场景中实现了应用程序购买,并且在从商店场景切换到另一个场景时遇到了问题,它似乎使游戏崩溃并给我这个错误
Thread 1: EXC_BAD_ACCESS (code=1, address=0x840f8010)
或者它给了我其他错误的多个版本,例如:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x3f8)
它有时也会给我一个错误,像这样更改子类中的行
当我注释掉子类中搜索应用程序购买信息或将手机置于飞行模式的代码时,它工作正常并且问题消失了。
我有一个 SKnode 的子类,它获取有关可购买商品的信息,然后通过使用 SKLabels 和 sprite 节点显示它,以显示商店中购买的图片,如下所示:
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)
}
}
然后使用以下代码将它们显示在商店场景中:
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)
商店的主要类
商店主类也有用于购买产品的应用内购买代码,也可以像在子类中一样搜索产品信息,如下所示
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")
}
}
}
我是否正在以正确的方式执行此操作,或者是否有更好的方法来执行此操作以及如何解决我遇到的崩溃问题?
编辑
编辑 2
编辑 3
编辑 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")
}
}
}
}
最佳答案
在您的游戏场景中拥有所有 StoreKit 代码会使您更难隔离您遇到的问题。我建议您创建一个新的 swift 文件,我们将其称为 PurchaseService,并使用如下静态实例:
class PurchaseService {
static let session = PurchaseService()
var products = [SKProduct]()
// code
}
您可以在此处实现所有与采购相关的逻辑。我通常使用 getPurchases 函数从商店加载可用的购买,并从 AppDelegate.swift 文件的应用程序函数调用它。这确保您的购买很早就加载并且在您需要它们的第一时间就准备好(因为您创建了一个静态实例,您可以在需要通过 PurchaseService.session 进行购买时随时引用它...)
要获取价格,您可以使用一个函数来遍历您的产品变量并检查产品 ID:
func price(for productID:String)->Double{
if products.count>0 {
for product in products {
if product.productIdentifier == productID {
return product.price.doubleValue
}
}
}
}
如果您遵守 SKProductRequestDelegate 协议(protocol),则无需有条件地将 self 转换为它:
// unnecessary: request.delegate = self as? SKProductsRequestDelegate
request.delegate = self
想知道您是否公开了 productRequest 方法,因为在请求返回时,SKProductResponse 对象自身不再可用。
关于您项目中的 Objective-C 代码:我看到您可能正在使用 Firebase(我从您的控制台消息推断)并且它有一些 Objective-C 的零碎部分。
关于ios - 更改场景时,应用内购买会导致应用崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47129841/
我正在尝试使用 Spark 从 Cassandra 读取数据。 DataFrame rdf = sqlContext.read().option("keyspace", "readypulse
这是代码: void i_log_ (int error, const char * file, int line, const char * fmt, ...) { /* Get erro
我必须调试一个严重依赖 Gtk 的程序。问题是由于某些原因,在使用 GtkWindow 对象时开始出现许多运行时警告。问题是,即使 Gtk 提示严重错误,它也不会因这些错误而中止。我没有代码库的更改历
我正在尝试从已有效编译和链接的程序中检索二进制文件。我已经通过 GL_PROGRAM_BINARY_LENGTH 收到了它的长度。该文档说有两个实例可能会发生 GL_INVALID_OPERATION
我有一个托管在 Azure 环境中的服务。我正在使用控制台应用程序使用该服务。这样做时,我得到了异常: "The requested service, 'http://xxxx-d.yyyy.be/S
我有以下代码,它被 SEGV 信号杀死。使用调试器表明它被 main() 中的第一个 sem_init() 杀死。如果我注释掉第一个 sem_init() ,第二个会导致同样的问题。我试图弄清楚是什么
目前我正在编写一个应用程序(目标 iOS 6,启用 ARC),它使用 JSON 进行数据传输,使用核心数据进行持久存储。 JSON 数据由 PHP 脚本通过 json_encode 从 MySQL 数
我对 Xamarin.Forms 还是很陌生。我在出现的主页上有一个非常简单的功能 async public Task BaseAppearing() { if (UserID
这是我的代码的简化版本。 public class MainActivity extends ActionBarActivity { private ArrayList entry = new Arr
我想弄明白为什么我的两个 Java 库很难很好地协同工作。这是场景: 库 1 有一个类 A,其构造函数如下: public A(Object obj) { /* boilerplate */ } 在以
如果网站不需要身份验证,我的代码可以正常工作,如果需要,则在打印“已创建凭据”后会立即出现 EXC_BAD_ACCESS 错误。我不会发布任何内容,并且此代码是直接从文档中复制的 - 知道出了什么问题
我在使用 NSArray 填充 UITableView 时遇到问题。我确信我正在做一些愚蠢的事情,但我无法弄清楚。当我尝试进行简单的计数时,我得到了 EXC_BAD_ACCESS,我知道这是因为我试图
我在 UITableViewCell 上有一个 UITextField,在另一个单元格上有一个按钮。 我单击 UITextField(出现键盘)。 UITextField 调用了以下方法: - (BO
我有一个应用程序出现间歇性崩溃。崩溃日志显示了一个堆栈跟踪,这对我来说很难破译,因此希望其他人看到了这一点并能为我指出正确的方向。 基本上,应用程序在启动时执行反向地理编码请求,以在标签中显示用户的位
我开发了一个 CGImage,当程序使用以下命令将其显示在屏幕上时它工作正常: [output_view.layer performSelectorOnMainThread:@selector(set
我正在使用新的 EncryptedSharedPreferences以谷歌推荐的方式上课: private fun securePrefs(context: Context): SharedPrefe
我有一个中继器,里面有一些控件,其中一个是文本框。我正在尝试使用 jquery 获取文本框,我的代码如下所示: $("#").click(function (event) {}); 但我总是得到 nu
在以下场景中观察到 TTS 初始化错误,太随机了。 已安装 TTS 引擎,存在语音集,并且可以从辅助功能选项中播放示例 tts。 TTS 初始化在之前初始化和播放的同一设备上随机失败。 在不同的设备(
maven pom.xml org.openjdk.jol jol-core 0.10 Java 类: public class MyObjectData { pr
在不担心冲突的情况下,可以使用 MD5 作为哈希值,字符串长度最多为多少? 这可能是通过为特定字符集中的每个可能的字符串生成 MD5 哈希来计算的,长度不断增加,直到哈希第二次出现(冲突)。没有冲突的
我是一名优秀的程序员,十分优秀!