#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
}
}