#swift #xcode #in-app-purchase #nsnotificationcenter
#swift #xcode #покупка в приложении #nsnotificationcenter
Вопрос:
в настоящее время я работаю над своим первым проектом swift и меня смущает следующий код, я буду комментировать его построчно, чтобы показать, что я понимаю, но в целом я чувствую себя немного сбитым с толку.
Таким образом, для запуска используется уведомление, основанное на значении из вспомогательного класса IAP.
NotificationCenter.default.addObserver(self, selector: #selector(MasterViewController.handlePurchaseNotification(_:)),
name: NSNotification.Name(rawValue: IAPHelper.IAPHelperPurchaseNotification),object: nil
Итак, это метод, который упоминается в приведенном выше nsnotification. Теперь мой первый вопрос: вызывается ли это автоматически при получении уведомления ns?. Вторая строка, я думаю, определяет идентификатор продукта как переменную, которую нельзя изменить, и guard присваивает ей определенный тип. Т.Е. в этом случае это должна быть строка.
2 строки, которые меня смущают, могли бы подумать, что это цикл for, но я не вижу его итерации, поэтому не уверен, что это делает. Я предполагаю, что последняя строка является действием, когда она соответствует проверкам.
func handlePurchaseNotification(_ notification: Notification) {
guard let productID = notification.object as? String else { return }
for (index, product) in products.enumerated() {
guard product.productIdentifier == productID else { continue }
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .fade)
}
Спасибо всем за помощь, любые объяснения приветствуются!
Ответ №1:
вызывается ли это автоматически при получении уведомления ns?
Да, в этом весь смысл addObserver(_:selector:name:object:)
Я прокомментировал код:
func handlePurchaseNotification(_ notification: Notification) {
// convert notification.object to string if you can, and call it productID. Otherwise return
guard let productID = notification.object as? String else { return }
// products.enumerated() would yield something like
// [(0, productA), (1, productB), (2, productC)]
// This array is iterated, with the index and product being set to the values from each tuple in turn
for (index, product) in products.enumerated() {
// check if the current product's productIdentifier is == to productID, otherwise keep searching
guard product.productIdentifier == productID else { continue }
// if we get to here, it's implied the productIdentifier == productID
// reload the row with the corresponding index
tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .fade)
}
Эта последняя строка немного глупая. reloadRows(at:with:)
принимает в Array<IndexPath>
качестве аргумента. В этом коде на каждой итерации создается новый массив, содержащий только один элемент, созданный на этой итерации. Было бы гораздо эффективнее создать массив, содержащий все IndexPath
экземпляры, а затем вызвать reloadRows(at:with:)
только один раз в конце.
Вот мой взгляд на этот метод, которому, я думаю, гораздо проще следовать:
func handlePurchaseNotification(_ notification: Notification) {
guard let desiredID = notification.object as? String else { return }
let staleRows = products.enumerated() // convert an array of products into an array tuples of indices and products
.filter{ _, product in product.ID == desiredID } // filter to keep only products with the desired ID
.map{ index, _ in IndexPath(row: index, section: 0) } // create an array of IndexPath instances from the indexes
tableView.reloadRows(at: staleRows, with: .fade)
}