Swift запутался в том, что делает этот код

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