Home About Contact

 

Creating views in a loop with ForEach, Identifiable and List in SwiftUI

2 min read

In SwiftUI, you cannot use a control flow statement within a ViewBuilder closure. For example, you need to loop over a collection of data and create views accordingly. The screenshot below shows that a typical for loop in swift code is used but your Xcode will show you error as below.

To do that, SwiftUI comes with a handy struct ForEach that can be used to loop over a collection of identified data to create views. Such as follows:

let persons = ["John Yew", "Charlie Chow", "Michelle J Fox","Ashley Lee"]
ForEach(persons, id:\.self){ person in
   Text("\(person)")
}

ForEach has three initializers. One of them, as shown above, which you supply the first parameter as the collection of data and the second parameter is the unique identifier for each element in the collection. The id is what SwiftUI needs to distinguish the views inside ForEach.

Please note that the above, .\self is used, meaning each element is uniquely identified by itself.

Another example below shows a custom type, struct Person :

struct Person{
    var id : Int
    var name : String
}

When used with ForEach, if we need to use its id as the unique identifier then we must supply each with a unique value as follows:

let persons = [Person(id:1, name: "John Yew"),
Person(id:2, name: "Sam Wong"), 
Person(id:3, name: "Ashley Joe"), 
Person(id:4, name: "Jessy Lee")]

ForEach(persons, id:\.id){ person in
   Text("\(person.name)")
}

Or we can set the id of the Person struct with a UUID, which guarantees it to be unique. As follows:

struct Person{
    var id = UUID()
    var name : String
}

So, we don’t need to supply each with a unique id when initializing Person as follows:

let persons = [Person(name: "John Yew"),
Person(name: "Sam Wong"), 
Person(name: "Ashley Joe"), 
Person(name: "Jessy Lee")]

ForEach(persons, id:\.id){ person in
   Text("\(person.name)")
}

The second initializer of ForEach only needs the first parameter as a collection of data of its elements of type conforming to Identifiable protocol. Such as we make struct Person to conform to Identifiable.

struct Person : Identifiable{
    var id = UUID()
    var name : String
}

So it can be used with ForEach without supplying the id as follows:

let persons = [Person(name: "John Yew"),
Person(name: "Sam Wong"), 
Person(name: "Ashley Joe"), 
Person(name: "Jessy Lee")]

ForEach(persons){ person in
   Text("\(person.name)")
}

The third initializer of ForEach is which you can provide it a Range of Int (which does not include its upper bound) as follows:

ForEach(1..<5){ num in
   Text("Line \(num)")
}

If you want to use a ClosedRange of Int instead, which includes its upper bound, you'll need to specify itself as its unique identifier as follows:

ForEach(1...5, id:\.self){ num in
   Text("Line \(num)")
}

List in SwiftUI also comes with the same three initializers as ForEach.

1. For example List is supplied with a collection of data, and the second parameter id must be supplied, so List can distinguish views inside it.

let persons = [Person(id:1, name: "John Yew"),
Person(id:2, name: "Sam Wong"), 
Person(id:3, name: "Ashley Joe"), 
Person(id:4, name: "Jessy Lee")]
List(persons, id:\.id){ person in
   Text("\(person.name)")
}

2. List can be supplied with a collection of data which each element of type conforming to Identifiable, therefore id is not needed for the second parameter, as follows:

List(persons){ person in
   Text("\(person.name)")
}

3. List is supplied with a Range of Int.

List((1..<5)){ n in
   Text("Line \(n)")
}

Similarly, when supplied with a CloseRange of Int, the second parameter id is supplied with itself as the unique id as follows:

List(1...6, id:\.self){ n in
   Text("Line \(n)")
}

And of course, you can also use ForEach inside List view without using the above-mentioned initializers, such as:

List {
   ForEach ((1..<6)){ n in 
      Text("Line \(n)")
   }
}

Spread the love
Posted on December 27, 2020 By Christopher Chee

3 thoughts on “Creating views in a loop with ForEach, Identifiable and List in SwiftUI”

Please leave us your comments below, if you find any errors or mistakes with this post. Or you have better idea to suggest for better result etc.


Our FB Twitter Our IG Copyright © 2024