3

I have the following object as a var events = [[EventLog]] and I need to loop through each inner-array and display them in a section. For example, events[0] might have events[0][0].id events[0][1].id and events[0][2].id as values and events[1] may only have 1 element. This is the object that I've built for reference.

Model Object

class EventLog: Identifiable  {
    let id: UUID
    let ipAddress: String
    let date: String
    let getMethod: String
    let statusCode: String
    let secondStatusCode: String
    let versionInfo: String
    
    init(ipAddress: String, date: String, getMethod: String, statusCode: String, secondStatusCode: String, versionInfo: String ){
        self.id = UUID()
        self.ipAddress = ipAddress
        self.date = date
        self.getMethod = getMethod
        self.statusCode = statusCode
        self.secondStatusCode = secondStatusCode
        self.versionInfo = versionInfo
    }
}

Attempts At Using

Doing it this way results in this error: Referencing initializer 'init(_:content:)' on 'ForEach' requires that '[EventLog]' conform to 'Identifiable' It should be noted that the multidimensional array is stored on a ViewModel named landingPageVM which is not referenced here for the sake of brevity. It is however an @Published property of the view model.

ForEach(landingPageVM.eventLogs) { logs in
            ForEach(logs)) { log in
                Text(log.id.description)
            }
        }

1 Answer 1

3

If you can change your model to a struct instead of a class, you'll have an easier time with this (and a lot of other things in SwiftUI):

struct ContentView : View {
    @State var eventLogs : [[EventLog]] = []
    
    var body: some View {
        List {
            ForEach(eventLogs, id: \.self) { logs in
                Section(header: Text("\(logs.count)")) {
                    ForEach(logs) { log in
                        Text(log.id.description)
                    }
                }
            }
        }
    }
}

struct EventLog: Identifiable, Hashable  {
    let id: UUID
    let ipAddress: String
    let date: String
    let getMethod: String
    let statusCode: String
    let secondStatusCode: String
    let versionInfo: String
}

If you're stuck using a class for some reason, you can still get this behavior by doing something like:

extension EventLog : Hashable, Equatable {
    func hash(into hasher: inout Hasher) {
        hasher.combine(id) //etc
    }
    
    static func == (lhs: EventLog, rhs: EventLog) -> Bool {
        lhs.id == rhs.id && lhs.ipAddress == rhs.ipAddress //etc
    }
}

Details of the hash and == implementations may vary.

Sign up to request clarification or add additional context in comments.

4 Comments

How do I get that into a section? The change from class to struct definitely made a difference. Can you explain why? Also, would like the sections but I keep getting Int does not conform to View or something along those lines. Essentially the header for the section could be logs.count to identify each section or something along those lines.
Updated with Sections -- sounds like you were just trying to pass an Int instead of a Text
Ahhhh I didn't realize it could accept a view like that. Sweet! I'm loving SwiftUI more and more every day.
Re: struct vs class, with struct, the compiler generates a lot more synthesized behavior for you. Also, there's a huge difference (which is worth some research for you) on passing by reference vs passing by value. SwiftUI views tend to update looking at collections of value types (ie structs).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.