Store Kit在第二次请求时崩溃

时间:2014-11-27 15:02:05

标签: ios swift in-app-purchase sprite-kit storekit

我正在构建我的第一个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

1 个答案:

答案 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()

通过这种方式,您可以确保保留所有属性,并且不会再出现上述错误。