title: React Native / Swift - In App Purchases code crashing randomly in sandbox and testflight
body: <p>I am trying to include in app purchases in a react native app. I have tried <code>react-native-in-app-utils</code> and creating a native module in Swift. Both work but both seem very unstable. Random crashes with no errors in the Xcode console. Much more stable on test-flight but still crashes and seems to have no rhyme or reason. The bulk of the crashes happen on purchasing, but also happens a lot when retrieving purchases from Apple or restoring purchases. Here is my swift code for which I have an Objective C bridge to react-native:</p>
  
  <pre><code>// Create Product List
  struct ProductList {
    static let monthlySub       : String  = "monthlysubscription"
    static let threeMonthlySub  : String  = "threemonthlysubscription"
    static let sixMonthlySub    : String  = "sixmonthlysubscription"
    static let yearlySub        : String  = "yearlysubscription"
  
    static let products = [monthlySub, threeMonthlySub, sixMonthlySub, yearlySub]
  }
  
  @objc(StoreManager)
  class StoreManager: NSObject {
  
    var loadedProducts: Dictionary&lt;String, SKProduct&gt; = [:]
    // callback holders defined as optionals
    var purchaseCallbackHolder: RCTResponseSenderBlock? = nil
    var productsCallbackHolder: RCTResponseSenderBlock? = nil
    var restoreCallbackHolder: RCTResponseSenderBlock? = nil
  
    override init() {
      super.init()
      SKPaymentQueue.defaultQueue().addTransactionObserver(self)
    }
  
    @objc func getProductList(name: String, callback successCallback: RCTResponseSenderBlock){
      // check payments allowed
      if SKPaymentQueue.canMakePayments() {
        // products from static struct
        let products = NSSet(array: ProductList.products);
        // When request completes, calls the SKProductsRequestDelegate
        let request = SKProductsRequest(productIdentifiers: products as! Set&lt;String&gt;);
        productsCallbackHolder = successCallback
        request.delegate = self;
        request.start();
      }
    }
  
    @objc func purchaseProduct(productIdentifier: String, callback successCallback: RCTResponseSenderBlock) {
      let product = loadedProducts[productIdentifier as String]!
      let payment = SKPayment(product: product)
      // add callback to holder
      purchaseCallbackHolder = successCallback
      // Triggers SKPaymentTransactionObserver
      SKPaymentQueue.defaultQueue().addPayment(payment)
    }
  
    @objc func restorePurchases(name:String, callback successCallback: RCTResponseSenderBlock){
      restoreCallbackHolder = successCallback
      print("Restoring Purchases")
      SKPaymentQueue.defaultQueue().restoreCompletedTransactions()
    }
  
  
    @objc func validatePurchases(name:String, callback successCallback: RCTResponseSenderBlock) -&gt; Void {
  
      let receiptUrl = NSBundle.mainBundle().appStoreReceiptURL
      let receipt: NSData = NSData(contentsOfURL:receiptUrl!)!
      let receiptdata: NSString = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
  
      // Pass Base64 encoded string back to JS
      successCallback([receiptdata])
  
    }
  
    func updateWithProducts(products: [SKProduct]) {
  
      var productIdentifiers: Dictionary&lt;String, NSNumber&gt; = [:]
      for product in products {
        loadedProducts[product.productIdentifier] = product
        productIdentifiers[product.productIdentifier] = product.price
      }
      productsCallbackHolder?([productIdentifiers])
    }
  
  
  }
  
  extension StoreManager: SKProductsRequestDelegate {
    func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
      // products retrieved from App store
      let appProducts = response.products
      if appProducts.count != 0 {
        for product in appProducts{
          print(product.productIdentifier)
        }
        print(appProducts)
        updateWithProducts(appProducts)
      }
      else {
        // return error/info to react native
        print("no products received from store")
      }
    }
  }
  extension StoreManager: SKPaymentTransactionObserver {
    func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction])    {
      print("Received Payment Transaction Response from Apple");
      for transaction:AnyObject in transactions {
        // check object is a transaction first
        if let trans:SKPaymentTransaction = transaction as? SKPaymentTransaction{
          switch trans.transactionState {
          case .Purchased:
            print("Product Purchased");
            SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
            break;
          case .Failed:
            print("Purchased Failed");
            SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
            break;
          case .Restored:
            print("Purchases Restored");
            SKPaymentQueue.defaultQueue().finishTransaction(transaction as! SKPaymentTransaction)
          default:
            break;
          }
        }
        // invoke any callback waiting to be called
        purchaseCallbackHolder?([])
        purchaseCallbackHolder = nil
        restoreCallbackHolder?([])
        restoreCallbackHolder = nil
      }
  
    }
  }
  </code></pre>
  
  <p>Any help would be much appreciated!</p>
  
  <p><strong>Update:</strong> I have a stack trace of the crash below</p>
  
  <pre><code>AppName[1788:581487] *** -[StoreManager respondsToSelector:]: message sent to deallocated instance 0x14d43f80
  (lldb) bt
  * thread #4: tid = 0x8df6f, 0x25750ffe CoreFoundation`___forwarding___ + 530, queue = 'com.facebook.react.StoreManagerQueue', stop reason = EXC_BREAKPOINT (code=EXC_ARM_BREAKPOINT, subcode=0xdefe)
    * frame #0: 0x25750ffe CoreFoundation`___forwarding___ + 530
      frame #1: 0x2567b298 CoreFoundation`_CF_forwarding_prep_0 + 24
      frame #2: 0x2f103f1e StoreKit`__NotifyObserverAboutChanges + 66
      frame #3: 0x2565bc08 CoreFoundation`CFArrayApplyFunction + 36
      frame #4: 0x2f103ecc StoreKit`-[SKPaymentQueue _notifyObserversAboutChanges:sendUpdatedDownloads:] + 128
      frame #5: 0x2f1028e8 StoreKit`-[SKPaymentQueue addPayment:] + 320
      frame #6: 0x00106438 AppName`StoreManager.purchaseProduct(productIdentifier="iosmonthlysubscription799", successCallback=0x00106694 AppName`partial apply forwarder for reabstraction thunk helper from @callee_unowned @convention(block) (@unowned Swift.ImplicitlyUnwrappedOptional&lt;__ObjC.NSArray&gt;) -&gt; (@unowned ()) to @callee_owned (@owned Swift.ImplicitlyUnwrappedOptional&lt;Swift.Array&lt;Swift.AnyObject&gt;&gt;) -&gt; (@unowned ()) with unmangled suffix ".40" at inAppPayments.swift, self=0x14d0a990) -&gt; ()) -&gt; () + 1168 at inAppPayments.swift:54
      frame #7: 0x00106634 AppName`@objc StoreManager.purchaseProduct(String, callback : ([AnyObject]!) -&gt; ()) -&gt; () + 240 at inAppPayments.swift:0
      frame #8: 0x25752664 CoreFoundation`__invoking___ + 68
      frame #9: 0x256778bc CoreFoundation`-[NSInvocation invoke] + 292
      frame #10: 0x2567b356 CoreFoundation`-[NSInvocation invokeWithTarget:] + 50
      frame #11: 0x001672d6 AppName`-[RCTModuleMethod invokeWithBridge:module:arguments:](self=0x14fdba90, _cmd="invokeWithBridge:module:arguments:", bridge=0x14faa1a0, module=0x14d0a990, arguments=@"2 elements") + 1636 at RCTModuleMethod.m:489
      frame #12: 0x001abaea AppName`-[RCTBatchedBridge _handleRequestNumber:moduleID:methodID:params:](self=0x14faa1a0, _cmd="_handleRequestNumber:moduleID:methodID:params:", i=6, moduleID=77, methodID=3, params=@"2 elements") + 926 at RCTBatchedBridge.m:987
      frame #13: 0x001aae44 AppName`__33-[RCTBatchedBridge handleBuffer:]_block_invoke.452(.block_descriptor=&lt;unavailable&gt;) + 1028 at RCTBatchedBridge.m:915
      frame #14: 0x00b9bba6 libdispatch.dylib`_dispatch_call_block_and_release + 10
      frame #15: 0x00ba64aa libdispatch.dylib`_dispatch_queue_drain + 2014
      frame #16: 0x00b9ede2 libdispatch.dylib`_dispatch_queue_invoke + 282
      frame #17: 0x00ba799e libdispatch.dylib`_dispatch_root_queue_drain + 426
      frame #18: 0x00ba77f0 libdispatch.dylib`_dispatch_worker_thread3 + 100
      frame #19: 0x2547ee0c libsystem_pthread.dylib`_pthread_wqthread + 1024
      frame #20: 0x2547e9fc libsystem_pthread.dylib`start_wqthread + 8
  </code></pre>
  
  <p>Seems to be crashing because my callback references are optionals? This is Swift which is called by an Objective C bridge. I believe Objective C has no concept of optionals. </p>
  
  <p><code>var purchaseCallbackHolder: RCTResponseSenderBlock? = nil</code></p>
  
  <p>Is there a better way to do this? Thanks again</p>