1

Having trouble understanding the closure in UICollectionViewDiffableDataSource, particularly what's being passed into it. All of the tutorials I can find explain what to type but not why, and I'm still a bit new to Swift and programming.

I'm following along with Paul Hudson's tutorial (he's making an app store made up of App objects) and in createDataSource() he writes:

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

My confusion on the closure's parameters is about where they're coming from:

  • He happens to declare collectionView as a global variable elsewhere in the View Controller. So I suppose that's required for this to be passed in?
  • Where is indexPath coming from here?
  • Most confusing: how does it know what app is? As far as I can tell it's not declared anywhere. This is the case in all the tutorials I've seen. Where in the world is the concept of an instance of App coming from?

Thank you a ton to anyone who can help me grasp this, I've been scouring tutorials but its been tough to figure out the mechanics here.

JBZic
  • 53
  • 6

1 Answers1

1

This is an initializer for the object. It looks like this:

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

It's using generics which are supplied as such <Section, App> Section in this example is defined as:

 import Foundation

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

App is defined in the application in this example is:

  import Foundation

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

These types are supplied to the initializer to fulfill the type requirements of the generic init.

Notice the object now understands how to get information from the UICollectionView.

It can now call the block with parameters:

  1. The collection view you supplied.
  2. The IndexPath for the items by querying the sections by the type Section. 2a. The row information by querying the collection view for type App in section.
  3. Query the collectionView for the instance of App at indexPath.

Check out Generic Types to get a better understanding.

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

SeaSpell
  • 678
  • 3
  • 9
  • For #3, how does it know `app` is an instance of `App`? Is it just always the lowercase spelling of the class/struct? Nowhere does he say `app = App` (even though it's probably what you'd call it.) Thanks a ton for the response by the way, I think the first two make sense now. – JBZic Jun 30 '21 at 19:34
  • The app in the closure can be named anything you want. He just gave it the name app. Swift know the type because of the < ItemIdentifierType>. If you didn't give the variables a name swift would have named them $0, $1, and $2 respectively. – SeaSpell Jun 30 '21 at 20:12
  • The arguments are supplied by the object when the closure is called, but the names are lost. Inside the object they're probably called collectionView, idxPath, item or something. When you call the closure it gets passed in but without names. You supply the names you want to use. You can change the name app to trushsnabarshablepressure if you want, but the type will still be the type you told swift it would be inside
    – SeaSpell Jun 30 '21 at 20:17
  • Swift doesn't necessarily need to know the type as long as it's Hashable but when it's passed it can be passed as whatever type was given. That way you don't have to cast using as when you want to use it. – SeaSpell Jun 30 '21 at 20:18
  • 1
    Thank you so much! Your comments were super helpful and really helped things click. – JBZic Jul 02 '21 at 21:36