我正在构建我的第一个Store Kit应用程序并出现崩溃问题:
该应用是一款精灵套装游戏
MainMenuScene.swift
中的我分配RemoveAdButton
点按时我拨打initPurchaseRemoveAds()
功能
MainMenuScene.swift e = SKPaymentQueue.defaultQueue()
func initPurchaseRemoveAds() {
let actionRotate = SKAction.rotateByAngle(CGFloat(M_2_PI), duration: 0.1)
let spin = SKAction.repeatActionForever(actionRotate)
self.loadingwheel.runAction(spin)
self.loadingwheel.hidden = false
NSNotificationCenter.defaultCenter().postNotificationName(KeyValueKeyClassification.NotificationBuyRemoveAd.rawValue, object: nil, userInfo: nil)
}
GameViewController.swift
var request : SKProductsRequest?
var queue : SKPaymentQueue. = SKPaymentQueue.defaultQueue()
// called through the notification (works!)
func initPurchase(notification: NSNotification) {
println("user clicked remove ads")
if SKPaymentQueue.canMakePayments() {
println("user can make payments")
self.request = SKProductsRequest(productIdentifiers: NSSet(object: PurchaseClassification.RemoveAdID.rawValue as String))
self.request?.delegate = self
self.request?.start()
} else {
println("user cannot make payments")
}
}
func restorePurchases() {
SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
}
func purchase(product : SKProduct) {
let payment = SKPayment(product: product)
SKPaymentQueue.defaultQueue().addTransactionObserver(self)
SKPaymentQueue.defaultQueue().addPayment(payment)
}
func productsRequest(request: SKProductsRequest!, didReceiveResponse response: SKProductsResponse!) {
var adprodfound : Bool = false
var count = response.products.count
if count > 0 {
for p in response.products {
if p is SKProduct {
var prod = p as SKProduct
if prod.productIdentifier == PurchaseClassification.RemoveAdID.rawValue as String {
println("remove ad product available")
adprodfound = true
purchase(prod)
}
}
}
}
if !adprodfound {
println("remove ad product not available")
}
}
func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue!) {
println("received restored transactions")
for t in queue.transactions {
if t is SKPaymentTransaction {
var trans = t as SKPaymentTransaction
if trans.transactionState == SKPaymentTransactionState.Restored {
println("transactionstate = restored")
removeAds()
break
}
}
}
}
func paymentQueue(queue: SKPaymentQueue!, updatedTransactions transactions: [AnyObject]!) {
for t in queue.transactions {
if t is SKPaymentTransaction {
var trans = t as SKPaymentTransaction
switch trans.transactionState {
case .Purchasing:
break
case .Purchased:
removeAds()
SKPaymentQueue.defaultQueue().finishTransaction(trans)
break
case .Restored:
SKPaymentQueue.defaultQueue().finishTransaction(trans)
case .Failed:
if trans.error.code != SKErrorPaymentCancelled {
println("Transaction state -> Cancelled")
}
stopWheel()
SKPaymentQueue.defaultQueue().finishTransaction(trans)
break
default:
stopWheel()
SKPaymentQueue.defaultQueue().finishTransaction(trans)
}
}
}
}
func stopWheel() {
println("stop wheel")
NSNotificationCenter.defaultCenter()。postNotificationName(KeyValueKeyClassification.NotificationStopWheel.rawValue,object:nil,userInfo:nil) }
func removeAds() {
stopWheel()
NSUserDefaults.standardUserDefaults().setBool(true, forKey: KeyValueKeyClassification.KeyAdsRemoved.rawValue)
NSNotificationCenter.defaultCenter().postNotificationName(KeyValueKeyClassification.NotificationRemoveAds.rawValue, object: nil, userInfo: nil)
}
问题
*完成一次购买工作正常
*如果我中止购买(车轮停止旋转,一切正常),然后再次点击RemoveAds
按钮,应用程序崩溃
错误再现:
输出:
user clicked remove ads
user can make payments
remove ad product available
stop wheel
user clicked remove ads
user can make payments
(lldb) bt
thread #1: tid = 0x3186, 0x0000000102abd00b libobjc.A.dylib`objc_msgSend + 11, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x0000000102abd00b libobjc.A.dylib`objc_msgSend + 11
frame #1: 0x000000010084eeee StoreKit`__34-[SKProductsRequest _handleReply:]_block_invoke + 52
frame #2: 0x0000000107070ba6 libdispatch.dylib`_dispatch_call_block_and_release + 12
frame #3: 0x000000010708e7f4 libdispatch.dylib`_dispatch_client_callout + 8
frame #4: 0x00000001070778fb libdispatch.dylib`_dispatch_main_queue_callback_4CF + 949
frame #5: 0x00000001012e9fe9 CoreFoundation`__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
frame #6: 0x00000001012aceeb CoreFoundation`__CFRunLoopRun + 2043
frame #7: 0x00000001012ac486 CoreFoundation`CFRunLoopRunSpecific + 470
frame #8: 0x00000001031819f0 GraphicsServices`GSEventRunModal + 161
frame #9: 0x000000010176e420 UIKit`UIApplicationMain + 1282
* frame #10: 0x000000010061a3ae shapesly`top_level_code + 78 at AppDelegate.swift:14
frame #11: 0x000000010061a3ea shapesly`main + 42 at AppDelegate.swift:0
frame #12: 0x00000001070c3145 libdyld.dylib`start + 1
(lldb)
错误:
[app.GameViewController retain]: message sent to deallocated instance 0x7fc2fc845880
答案 0 :(得分:7)
我相信你的问题是没有保留SKProductsRequest。
最佳解决方案是将StoreKit逻辑移动到辅助类:
class StoreKitHelper: NSObject,SKProductsRequestDelegate, SKPaymentTransactionObserver, SKRequestDelegate {
var request : SKProductsRequest?
var queue : SKPaymentQueue = SKPaymentQueue.defaultQueue()
class var defaultHelper : StoreKitHelper {
struct Static {
static let instance : StoreKitHelper = StoreKitHelper()
}
return Static.instance
}
override init() {
super.init()
}
func initPurchase() {
println("user clicked remove ads")
if SKPaymentQueue.canMakePayments() {
println("user can make payments")
self.request = SKProductsRequest(productIdentifiers: NSSet(object: PurchaseClassification.RemoveAdID.rawValue as String))
self.request?.delegate = self
self.request?.start()
} else {
println("user cannot make payments")
}
}
...
然后您可以在没有通知的情况下初始购买:
StoreKitHelper.defaultHelper.initPurchase()
通过这种方式,您可以确保保留所有属性,并且不会再出现上述错误。