ViewController respondsToSelector:购买消耗品时发送到已释放实例的消息
ViewController respondsToSelector: message sent to deallocated instance while buying consumable product
我在购买测试模式的产品时遇到了一些问题。我有 2 个视图控制器。 viewcontroller2 是 IAP class。购买硬币工作正常,它的显示在 viewcontroller1 中的标签中完美地购买了硬币。因此,当我切换到 viewcontroller1(我使用硬币的地方)并返回 viewcontroller2 并再次点击购买按钮购买硬币时,它崩溃了。
viewcontroller2:
import UIKit
import StoreKit
public var coins = NSUserDefaults.standardUserDefaults().integerForKey("coins")
public var ads = NSUserDefaults.standardUserDefaults().boolForKey("purchased")
class ViewController2: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver{
@IBOutlet var lblAd: UILabel!
@IBOutlet var lblCoinAmount: UILabel!
@IBOutlet var outRemoveAds: UIButton!
@IBOutlet var outAddCoins: UIButton!
// 1
override func viewDidLoad() {
super.viewDidLoad()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
outRemoveAds.enabled = false
outAddCoins.enabled = false
// Set IAPS
if(SKPaymentQueue.canMakePayments()) {
print("IAP is enabled, loading")
let productID:NSSet = NSSet(objects: "productId1", "productId2")
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
print("please enable IAPS")
}
lblCoinAmount.text = "\(coins)"
}
// 2
@IBAction func btnRemoveAds(sender: UIButton) {
for product in list {
let prodID = product.productIdentifier
if(prodID == "productId1") {
p = product
buyProduct()
break;
}
}
}
// 3
@IBAction func btnAddCoins(sender: UIButton) {
for product in list {
let prodID = product.productIdentifier
if(prodID == "productId2") {
p = product
buyProduct()
break;
}
}
}
// 4
func removeAds() {
//lblAd.removeFromSuperview()
let adsDefault = NSUserDefaults.standardUserDefaults()
adsDefault.setBool(true , forKey: "purchased")
adsDefault.synchronize()
}
// 5
func addCoins() {
coins = coins + 50
lblCoinAmount.text = "\(coins)"
let CoinsDefault = NSUserDefaults.standardUserDefaults()
CoinsDefault.setInteger(coins, forKey: "coins")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func RestorePurchases(sender: UIButton) {
//SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
var list = [SKProduct]()
var p = SKProduct()
func buyProduct() {
print("buy " + p.productIdentifier)
let pay = SKPayment(product: p)
//SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(pay)
}
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
print("product request")
let myProduct = response.products
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product )
}
outRemoveAds.enabled = true
outAddCoins.enabled = true
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
print("transactions restored")
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "productId1":
print("remove ads")
removeAds()
case "productId2":
print("add coins to account")
addCoins()
default:
print("IAP not setup")
}
}
}
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
print("add paymnet")
for transaction:AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
print(trans.error)
switch trans.transactionState {
case .Purchased:
print("buy, ok unlock iap here")
print(p.productIdentifier)
let prodID = p.productIdentifier as String
switch prodID {
case "productId1":
print("remove ads")
removeAds()
case "productId2":
print("add coins to account")
addCoins()
default:
print("IAP not setup")
}
queue.finishTransaction(trans)
break;
case .Failed:
print("buy error")
queue.finishTransaction(trans)
break;
default:
print("default")
break;
}
}
}
func finishTransaction(trans:SKPaymentTransaction)
{
print("finish trans")
SKPaymentQueue.defaultQueue().finishTransaction(trans)
}
func paymentQueue(queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction])
{
print("remove trans");
}
}
您可以使用 Instruments 来调查该错误。
分析您的应用程序 (Cmd ⌘+I) 然后选择名为 Zombies 的模板。
再次尝试使应用程序崩溃。您应该获得有关 "Zombie" 对象的更多信息,以及当时的堆栈状态。
如果您无法找出原因,您可以附上 Instruments 的屏幕截图,其中 Extended Details 窗格打开 - 如果可能,我会尽力提供帮助:)
在 viewcontrollers
的 deinit 函数中使用以下代码
SKPaymentQueue.defaultQueue().removeTransactionObserver
您错过了这一行:
override func viewWillDisappear(animated: Bool) {
SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
}
我在购买测试模式的产品时遇到了一些问题。我有 2 个视图控制器。 viewcontroller2 是 IAP class。购买硬币工作正常,它的显示在 viewcontroller1 中的标签中完美地购买了硬币。因此,当我切换到 viewcontroller1(我使用硬币的地方)并返回 viewcontroller2 并再次点击购买按钮购买硬币时,它崩溃了。
viewcontroller2:
import UIKit
import StoreKit
public var coins = NSUserDefaults.standardUserDefaults().integerForKey("coins")
public var ads = NSUserDefaults.standardUserDefaults().boolForKey("purchased")
class ViewController2: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver{
@IBOutlet var lblAd: UILabel!
@IBOutlet var lblCoinAmount: UILabel!
@IBOutlet var outRemoveAds: UIButton!
@IBOutlet var outAddCoins: UIButton!
// 1
override func viewDidLoad() {
super.viewDidLoad()
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
outRemoveAds.enabled = false
outAddCoins.enabled = false
// Set IAPS
if(SKPaymentQueue.canMakePayments()) {
print("IAP is enabled, loading")
let productID:NSSet = NSSet(objects: "productId1", "productId2")
let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
request.delegate = self
request.start()
} else {
print("please enable IAPS")
}
lblCoinAmount.text = "\(coins)"
}
// 2
@IBAction func btnRemoveAds(sender: UIButton) {
for product in list {
let prodID = product.productIdentifier
if(prodID == "productId1") {
p = product
buyProduct()
break;
}
}
}
// 3
@IBAction func btnAddCoins(sender: UIButton) {
for product in list {
let prodID = product.productIdentifier
if(prodID == "productId2") {
p = product
buyProduct()
break;
}
}
}
// 4
func removeAds() {
//lblAd.removeFromSuperview()
let adsDefault = NSUserDefaults.standardUserDefaults()
adsDefault.setBool(true , forKey: "purchased")
adsDefault.synchronize()
}
// 5
func addCoins() {
coins = coins + 50
lblCoinAmount.text = "\(coins)"
let CoinsDefault = NSUserDefaults.standardUserDefaults()
CoinsDefault.setInteger(coins, forKey: "coins")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func RestorePurchases(sender: UIButton) {
//SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
var list = [SKProduct]()
var p = SKProduct()
func buyProduct() {
print("buy " + p.productIdentifier)
let pay = SKPayment(product: p)
//SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(pay)
}
func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
print("product request")
let myProduct = response.products
for product in myProduct {
print("product added")
print(product.productIdentifier)
print(product.localizedTitle)
print(product.localizedDescription)
print(product.price)
list.append(product )
}
outRemoveAds.enabled = true
outAddCoins.enabled = true
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) {
print("transactions restored")
for transaction in queue.transactions {
let t: SKPaymentTransaction = transaction
let prodID = t.payment.productIdentifier as String
switch prodID {
case "productId1":
print("remove ads")
removeAds()
case "productId2":
print("add coins to account")
addCoins()
default:
print("IAP not setup")
}
}
}
func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
print("add paymnet")
for transaction:AnyObject in transactions {
let trans = transaction as! SKPaymentTransaction
print(trans.error)
switch trans.transactionState {
case .Purchased:
print("buy, ok unlock iap here")
print(p.productIdentifier)
let prodID = p.productIdentifier as String
switch prodID {
case "productId1":
print("remove ads")
removeAds()
case "productId2":
print("add coins to account")
addCoins()
default:
print("IAP not setup")
}
queue.finishTransaction(trans)
break;
case .Failed:
print("buy error")
queue.finishTransaction(trans)
break;
default:
print("default")
break;
}
}
}
func finishTransaction(trans:SKPaymentTransaction)
{
print("finish trans")
SKPaymentQueue.defaultQueue().finishTransaction(trans)
}
func paymentQueue(queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction])
{
print("remove trans");
}
}
您可以使用 Instruments 来调查该错误。 分析您的应用程序 (Cmd ⌘+I) 然后选择名为 Zombies 的模板。
再次尝试使应用程序崩溃。您应该获得有关 "Zombie" 对象的更多信息,以及当时的堆栈状态。 如果您无法找出原因,您可以附上 Instruments 的屏幕截图,其中 Extended Details 窗格打开 - 如果可能,我会尽力提供帮助:)
在 viewcontrollers
的 deinit 函数中使用以下代码SKPaymentQueue.defaultQueue().removeTransactionObserver
您错过了这一行:
override func viewWillDisappear(animated: Bool) {
SKPaymentQueue.defaultQueue().removeTransactionObserver(self)
}