Instagram / IGListKit

A data-driven UICollectionView framework for building fast and flexible lists.
https://instagram.github.io/IGListKit/
MIT License
12.86k stars 1.54k forks source link

Multiple Nested List Adapters inside ListBindingSectionController #1415

Open Smiller193 opened 4 years ago

Smiller193 commented 4 years ago

New issue checklist

General information

So this isn't really so much an issue and more of a how to. Thanks to this guide https://instagram.github.io/IGListKit/modeling-and-binding.html I was able to take my Event object and render it using a ListBindingSectionController with the accompanying view models attached to the accompanying cells. Here is what my object looks like:

`class Event:NSObject{
    var key: String?
    let name: String
    let promoVideo: String
    var eventImages: [String]
    let eventDescription: String
    var weather: Weather?
    let streetAddress: String
    let city: String
    let state: String
    let zipCode: Int
    let price: Double
    let startTime: Date
    let endTime: Date
    var category: String
    var attendCount: Int
    var isAttending = false
    var eventTags: [String]?
    var userHost: [String]?
    var orgHost: [String]?
    var attendingUsers: [Attend]?
    var actions: [Action]?

    //init for event submission
    init?(key:String, name:String, eventImage:[String],promoVideo:String,eventDescription:String,streetAddress:String,city:String,state: String,zipCode: Int,startTime: Date, endTime: Date,price: Double,category: String,attendCount: Int,tags: [String]?,userHost: [String]?) {

        self.key = key
        self.name = name
        self.eventImages = eventImage
        self.promoVideo = promoVideo
        self.eventDescription = eventDescription
        self.streetAddress = streetAddress
        self.city = city
        self.state = state
        self.zipCode = zipCode
        self.startTime = startTime
        self.endTime = endTime
        self.price = price
        self.category = category
        self.attendCount = attendCount
        self.eventTags = tags
        self.userHost = userHost
    }

    init?(snapshot: DataSnapshot) {
        guard let dict = snapshot.value as? [String : Any],
            let name = dict["eventName"] as? String,
            let eventDescription = dict["eventDescription"] as? String,
            let promoVideo = dict["eventPromo"] as? String,
            let eventImages = dict["eventImageURL"] as? [String],
            let category = dict["eventCategory"] as? String,
            let streetAddress = dict["eventStreetAddress"] as? String,
            let city = dict["eventCity"] as? String,
            let state = dict["eventState"] as? String,
            let zipCode = dict["eventZip"] as? Int,
            let attendCount = dict["attend:count"] as? Int,
            let price = dict["eventPrice"] as? Double,
            let eventTime = dict["eventDatetime"] as? [String: Any],
            let startTime = eventTime["start"] as? Double,
            let endTime = eventTime["end"] as? Double
            else { return nil }
        self.key = snapshot.key
        self.name = name
        self.eventDescription = eventDescription
        self.eventImages = eventImages
        self.promoVideo = promoVideo
        self.streetAddress = streetAddress
        self.city = city
        self.state = state
        self.zipCode = zipCode
        self.attendCount = attendCount
        self.category = category
        self.price = price
        self.startTime = Date(timeIntervalSince1970: startTime)
        self.endTime =  Date(timeIntervalSince1970: endTime)
        //tags
        if let tags = dict["tags"] as? [String] {
            self.eventTags = tags
        }
        //user host
        if let users = dict["host_user"] as? [String] {
            self.userHost = users
        }
        //org host
        if let orgs = dict["host_org"] as? [String] {
            self.orgHost = orgs
        }
    }

    var eventDictionary: [String: Any]{
          let timeDict = ["endTime":endTime.timeIntervalSince1970, "startTime": startTime.timeIntervalSince1970]

          return ["name":name,"images" : eventImages,
                  "eventDescription": eventDescription, "attendCount": attendCount,
                  "streetAddress": streetAddress,"zipCode": zipCode,"price":price,
                  "state": state, "city": city, "promoVideo": promoVideo, "category":category,"eventDatetime": timeDict]
      }

}

extension Event {
    static public func ==(rhs: Event, lhs: Event) ->Bool{
        return rhs.key == lhs.key
    }
}

extension Event: ListDiffable{
    public func diffIdentifier() -> NSObjectProtocol {
        return key! as NSObjectProtocol
    }
    public func isEqual(toDiffableObject object: ListDiffable?) ->Bool{
        guard let object = object as? Event else {
            return false
        }
        return  self.key==object.key
    }
}`

As you can see there are certain properties that are arrays such as eventImages,attendingUsers,eventTags, etc. This means that I would need to implement multiple nested collectionViews/ list adapters inside the context of this EventDetailViewController. I was able to follow the code in the NestedAdapterViewController example in addition to this issue (https://github.com/Instagram/IGListKit/issues/1209) to achieve this task for eventImages but how would I do that for the rest of the nested collectionviews/adapters that will be present on this detail screen.

I mean I know it wouldn't be feasible to try to create multiple adapters so im really not sure where to start when it comes to creating more of these nested collectionViews and not completely screw something up.

Im thinking of doing some type of switch statement on the viewModel but im not entirely sure how that would work. Does anyone have any example code or is anyone able to point me in the right direction. If more of the code is needed to answer me properly lmk but most of my code looks similar to the mentioned examples.

Smiller193 commented 4 years ago

@weyert @iperry90

Smiller193 commented 4 years ago

okay I actually figured this out.

For anyone that cares to know all I did was create one nested adapter for each collectionViewCell that had a UICollectionView nested in it. Following that I assigned the nested collectionView to the collectionView handled by the appropriate adapter.

After that I basically just did a switch on the viewModel and assigned the appropriate data and section controller based off the viewModels that I want to be nested.