Откуда берутся параметры в закрытии UICollectionViewDiffableDataSource?

#ios #swift #uicollectionview #uikit #uicollectionviewdiffabledatasource

Вопрос:

Возникли проблемы с пониманием закрытия UICollectionViewDiffableDataSource , особенно того, что в него передается. Все учебники, которые я могу найти, объясняют, что печатать, но не почему, и я все еще немного новичок в Swift и программировании.

Я следую вместе с учебником Пола Хадсона (он создает магазин приложений, состоящий из App объектов), и в createDataSource() нем он пишет:

 dataSource = UICollectionViewDiffableDataSource<Section, App>(collectionView: collectionView)
  { collectionView, indexPath, app in 
    //rest of the closure
  }
 

Мое замешательство в параметрах закрытия связано с тем, откуда они берутся:

  • Он случайно объявляется collectionView как глобальная переменная в другом месте контроллера представления. Так что, я полагаю, это необходимо для того, чтобы это было передано?
  • Откуда все это indexPath берется?
  • Самое непонятное: откуда он знает, что app есть? Насколько я могу судить, это нигде не объявлено. Так обстоит дело во всех учебниках, которые я видел. Откуда в мире App взялось понятие примера?

Огромное спасибо всем, кто может помочь мне понять это, я просматривал учебники, но здесь было сложно разобраться в механике.

Ответ №1:

Это инициализатор для объекта. Это выглядит так:

   UICollectionViewDiffableDataSource<<#SectionIdentifierType: Hashable#>, <#ItemIdentifierType: Hashable#>>(collectionView: collectionView)
 

Он использует дженерики, которые поставляются как таковые <Раздел, приложение>
Раздел в этом примере определяется как:

  import Foundation

  struct Section: Decodable, Hashable {
     let id: Int
     let type: String
     let title: String
     let subtitle: String
     let items: [App]
  }
 

Приложение определено в приложении в этом примере:

   import Foundation

  struct App: Decodable, Hashable {
      let id: Int
      let tagline: String
      let name: String
      let subheading: String
      let image: String
      let iap: Bool
  }
 

Эти типы передаются инициализатору для выполнения требований к типу универсального инициализатора.

Обратите внимание, что объект теперь понимает, как получать информацию из UICollectionView.

Теперь он может вызывать блок с параметрами:

  1. Представление коллекции, которое вы предоставили.
  2. indexPath для элементов путем запроса разделов по типу раздела. 2а. Информацию о строке, запросив представление коллекции для приложения типа в разделе.
  3. Запросите представление коллекции для экземпляра приложения в indexPath.

Ознакомьтесь с общими типами, чтобы получить лучшее представление.

https://docs.swift.org/swift-book/LanguageGuide/Generics.html

Комментарии:

1. Для #3, как он узнает app , что это экземпляр App ? Всегда ли это просто написание в нижнем регистре класса/структуры? Нигде он не говорит app = App (хотя, вероятно, это то, что вы бы назвали). Кстати, огромное спасибо за ответ, я думаю, что первые два теперь имеют смысл.

2. Приложение в закрытии можно назвать как угодно. Он просто дал ему название app. Swift знает тип из-за < ItemIdentifierType>. Если бы вы не дали переменным имя, swift назвал бы их $0, $1 и $2 соответственно.

3. Аргументы предоставляются объектом при вызове закрытия, но имена теряются. Внутри объекта они, вероятно, называются CollectionView, idxPath, item или что-то в этом роде. Когда вы вызываете закрытие, оно передается, но без имен. Вы указываете имена, которые хотите использовать. Вы можете изменить название приложения на trushsnabarshablepressure, если хотите, но тип по-прежнему будет таким, как вы сказали swift, он будет внутри <Раздел, Приложение>

4. Swift необязательно знать тип, если он хэшируется, но когда он передается, его можно передать как любой заданный тип. Таким образом, вам не нужно будет использовать заклинание, когда вы хотите его использовать.

5. Большое вам спасибо! Ваши комментарии были очень полезны и действительно помогли делу сдвинуться с мертвой точки.