Store Kit在第二次请求时崩溃

Seb*_*ger 1 storekit in-app-purchase ios sprite-kit swift

我正在构建我的第一个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)
    }
Run Code Online (Sandbox Code Playgroud)

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")
Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)

问题
*购买工作正常一次*app崩溃如果我中止购买(车轮停止旋转,一切正常)然后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) 
Run Code Online (Sandbox Code Playgroud)

错误:

[app.GameViewController retain]: message sent to deallocated instance 0x7fc2fc845880
Run Code Online (Sandbox Code Playgroud)

Mob*_*Ben 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")
    }
}

...
Run Code Online (Sandbox Code Playgroud)

然后您可以在没有通知的情况下初始化购买:

StoreKitHelper.defaultHelper.initPurchase()
Run Code Online (Sandbox Code Playgroud)

这样,您可以确保保留所有属性,并且不会再出现上述错误.