4

For loop in SwiftUI using ForEach

 1 year ago
source link: https://sarunw.com/posts/swiftui-foreach/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

You can easily support sarunw.com by checking out this sponsor.

Artboard%201@2x.png

Sponsor sarunw.com and reach thousands of iOS developers.

How to create views using For loop in SwiftUI

When creating an app, there is a time when you want to create a repetitive view or a collection of views from an array of data. We can do that in SwiftUI with ForEach.

ForEach can create views on demand from an underlying collection of identified data.

Identified data that work with ForEach can be classified into three groups.

Create views from a range of integer

The first initializer allows us to create views from a range of integers.

Here is the example using ForEach to loop over a range of 1..<11, then we create a text view from an integer within that range.

struct ContentView: View {
var body: some View {
VStack {
ForEach(1..<11) { index in
Text("Item \(index)")
}
}
}
}
Create ten text views using a range.

Create ten text views using a range.

ClosedRange won't work with ForEach, e.g., 1...10.

If you try using a ClosedRange, you will get the following error.

Cannot convert value of type 'ClosedRange<Int>' to expected argument type 'Range<Int>'
struct ContentView: View {
var body: some View {
VStack {
// Cannot convert value of type 'ClosedRange<Int>' to expected argument type 'Range<Int>'
ForEach(1...10) { index in
Text("Item \(index)")
}
}
}
}

Create views from an Identifiable data

Identifiable is a protocol that ask for one thing, a stable identity to a class or value type.

Identity can range from a database id, a book's ISBN, or a user's identity number.

The only thing you need to do is to make your data conform to the Identifiable protocol.

Identifiable protocol required two things.

  1. An variable name id of type ID.
  2. ID must be hashable (Conform to Hashable protocol).
public protocol Identifiable {

/// A type representing the stable identity of the entity associated with
/// an instance.
associatedtype ID : Hashable

/// The stable identity of the entity associated with this instance.
var id: Self.ID { get }
}

If your data has a property that you can uniquely identify the data, e.g., id, ISBN, or SKU, you can make your data conform to the Identifiable protocol. Then use a collection of that data in a ForEach.

Here is a Book model where we use an ISBN as an id.

struct Book: Identifiable {
var id: String {
return isbn
}

let isbn: String
let name: String
}

And here is an example where we use a collection of Book in a ForEach.

struct ContentView: View {
let books = [
Book(isbn: "0135264022", name: "iOS Programming: The Big Nerd Ranch Guide"),
Book(isbn: "0439708184", name: "Harry Potter and the Sorcerer's Stone"),
Book(isbn: "0358439191", name: "The Lord of the Rings 3-Book Paperback Box Set")
]

var body: some View {
List {
ForEach(books) { book in
Text(book.name)
}
}
}
}
ForEach with identifiable data.

ForEach with identifiable data.

You can easily support sarunw.com by checking out this sponsor.

Artboard%201@2x.png

Sponsor sarunw.com and reach thousands of iOS developers.

Create views from any data with a keypath to the data's identity

If you have a primitive or simple data that you don't want to conform to the Identifiable protocol, ForEach has an option for you to explicitly provide a key path to property that can uniquely identify that data.

In the following example, we have an array of color names that we want users to pick from. A simple string is sufficient for the picker, and I don't want to bother creating a new type for it. So, I use the \.self keypath, which references to string itself as an identity.

struct ContentView: View {
var colors = ["Red", "Green", "Blue"]
@State private var selectedColor = "Red"

var body: some View {
VStack {
Picker("Please select a color", selection: $selectedColor) {
// 1
ForEach(colors, id: \.self) {
Text($0)
}
}
.pickerStyle(.wheel)
Text("You selected: \(selectedColor)")
}
}
}

1 We provide a self key path \.self as an id.

ForEach with keypath.

ForEach with keypath.

\.self is a special path that can refer to an instance instead of a property, which is a string in this case.

You can read more about the key path in Swift KeyPath.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK