For In Loops in Viewbuilder?

Hi,

I cannot use “for in loops” in the Viewbuilder, so I need to put it in a function - am I right ?

Is there a possibility to filter (maybe with “where”) with a ForEach loop ?
I need to access a specific Element inside an Array (unfortunately the array looks like this → Picture)
I only need the first “Link” of the array. (the array MAP has an array always with “name” and “link”, but I only need the first Link.

What kind of loop would be the best for that ?

List {
ForEach(model.images.map, id:.name) { r in
VStack{
Text(“Name: (r.name)”)
Text(“Link: (r.link)”)
}
}
}

If you always only want the link property from the first item in the map array, then you don’t need a loop at all:

let link = model.images.maps.first?.link

//or

let link = model.images.maps.first!.link

//or

if let link = model.images.maps.first.link {
    //do something with link
}

//or

guard let link = model.images.maps.first.link else {
    //exit the current scope
}
//do something with link

But your SwiftUI View code seems do indicate that you do want a loop. Can you clarify exactly what you are trying to do?

1 Like

Thank you :slight_smile:
This is perfect with “first” and “last” I get the result what I want.
How could I access the third item ?

let link = model.images.map.[3]!.link

doesn’t seem to work.

Well, you wouldn’t do it the same way. Every array has a first and last element that is either nil or is an actual element. So every array has those properties that return 'Element?`

But not every array has a third, for instance, element. Some might only have 1 or 2. But using code like this:

let link = model.images.maps[3].link

will crash if there aren’t at least four items in the array. And since the default subscript for Array returns a real value rather than an Optional, you don’t even have the option to catch it with optional chaining or nil coalescing or a guard let or anything like that.

You need to either a) check your array bounds first and make sure you aren’t requesting an index outside those bounds, or b) write an extension on Array that creates a custom subscript to do that for you; something like this perhaps:

extension Array {
    public subscript(safe index: Int) -> Element? {
        guard (0..<endIndex).contains(index) else { return nil }
        
        return self[index]
    }
}

Sample usage:

struct MapElement {
    let name: String
    let link: String
}

let maps: [MapElement] = [
    MapElement(name: "First Map", link: UUID().uuidString),
    MapElement(name: "Second Map", link: UUID().uuidString),
    MapElement(name: "Third Map", link: UUID().uuidString),
    MapElement(name: "Fourth Map", link: UUID().uuidString),
]

let link = maps.first?.link //returns a value
let link3 = maps[safe: 3]?.link //returns a value
let link8 = maps[safe: 8]?.link //returns nil
1 Like