Как отключить кнопку, которая служит для покупки в приложении, не помещая ее в другой поток?

#swift #multithreading #in-app-purchase

#swift #многопоточность #покупка в приложении

Вопрос:

На панели навигации у меня есть кнопка, чтобы купить что-то в приложении.

 let acheterSuppressionPub: UIButton!
let acheterSuppressionPubButtonItem = UIBarButtonItem(customView: acheterSuppressionPub)
acheterSuppressionPub.addTarget(self, action: #selector(ProposerSupprimerPub), for: .touchUpInside)
@objc private func ProposerSupprimerPub() {
        if self.adsView.isHidden == false {
            afficherSupprimerForAllPubAlert()
        }
    }
 

В контроллере представления у меня есть это:

 // désactiver les boutons d'achats
        self.acheterSuppressionPub.isEnabled = false
        self.acheterSuppressionPub.isHidden = true
        
        // Purchase
        if(SKPaymentQueue.canMakePayments()) {
            print("IAP is enabled, loading")
            let productID: NSSet = NSSet(objects:
                "com.KingsFit-W.myfood.removeads")
            let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
            request.delegate = self
            request.start()
        } else {
            print("please enable IAPS")
        }
 

Вот предупреждение, чтобы предложить покупку:

 private func afficherSupprimerForAllPubAlert() {
        let alert = UIAlertController(title: NSLocalizedString("Souhaitez-vous enlever définitivement toutes les bannières publicitaires?", comment: ""), message: "n"   NSLocalizedString("Coût ", comment: "")   NSLocalizedString("xxx€", comment: ""), preferredStyle: .alert)
        
        alert.setValue(attributedString, forKey: "attributedTitle")
        
        alert.addAction(UIAlertAction(title: NSLocalizedString("Enlever la publicité", comment: ""), style: .default, handler: { (action) in
            print("remove ads began")
            for product in self.listeDesAchats {
                let prodID = product.productIdentifier
                if(prodID == "com.xxxxx.xxxxx.removeads") {
                    self.unAchat = product
                    self.buyProduct()
                }
            }
            
        }))
        
        alert.addAction(UIAlertAction(title: NSLocalizedString("Restorer mon achat", comment: ""), style: .default, handler: { (action) in
            
            SKPaymentQueue.default().add(self)
            SKPaymentQueue.default().restoreCompletedTransactions()
            
        }))
        
        alert.addAction(UIAlertAction(title: NSLocalizedString("Annuler", comment: ""), style: .cancel, handler: { (action) in
            return
        }))
        
        present(alert, animated: true)
    }
 

Вот функции для покупки продукта:

 func buyProduct() {
        print("Acheter "   unAchat.productIdentifier)
        let pay = SKPayment(product: unAchat)
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().add(pay as SKPayment)
    }

func removeAds() {
        self.adsView.isHidden = true
        self.acheterSuppressionPub.isHidden = true
        self.acheterSuppressionPub.isEnabled = false
    }
 

Вот функция, в которой заключается проблема:

 func productsRequest(_ request: SKProductsRequest, didReceive 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)
            
            listeDesAchats.append(product)
        }
        /////////////////////////////////////////////////////////////////
        self.acheterSuppressionPub.isEnabled = true // it says: -[UIButton setEnabled:] must be used from main thread only
        self.acheterSuppressionPub.isHidden = false
///////////////////////////////////////////////////////
    }
 

в нем говорится: -[UIButton setEnabled:] должен использоваться только из основного потока

Вот функции протокола:

 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 "com.KingsFit-W.myfood.removeads":
                    print("remove ads")
                    removeAds()
                default:
                    print("IAP not found")
            }
        }
    }

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        print("add payment")
        
        for transaction: AnyObject in transactions {
            let trans = transaction as! SKPaymentTransaction
            print(trans.error as Any)
            
            switch trans.transactionState {
            case .purchased:
                print("buy ok, unlock IAP HERE")
                print(unAchat.productIdentifier)
                
                let prodID = unAchat.productIdentifier
                switch prodID {
                    case "xxxxxxxxx.removeads":
                        print("remove ads")
                        removeAds()
                    default:
                        print("IAP not found")
                }
                queue.finishTransaction(trans)
            case .failed:
                print("buy error")
                queue.finishTransaction(trans)
                break
            default:
                print("Default")
                break
            }
        }
    }

 

Как я мог отключить и скрыть кнопку acheterSuppressionPub, не помещая ее в другой поток?
Я хочу отключить его, чтобы пользователь не мог нажать его снова, когда сетевой запрос еще не завершен.

Ответ №1:

Все взаимодействие с интерфейсом должно осуществляться в основном потоке. Стандартный способ перехода в основной поток для общения с интерфейсом:

 DispatchQueue.main.async {
    self.acheterSuppressionPub.isEnabled = true 
    self.acheterSuppressionPub.isHidden = false
}
 

Аналогично:

 func removeAds() {
    DispatchQueue.main.async {
        self.adsView.isHidden = true
        self.acheterSuppressionPub.isHidden = true
        self.acheterSuppressionPub.isEnabled = false
    }
}