Preview Crashed из-за ошибки при объявлении массива

Мне нужно в цикле вывести несколько блоков с VStack.

В данном случае, получаю ошибку Preview Crashed.

ScrollView {
    LazyVStack(alignment: .leading) {
        let posts = ["Запись", "Запись", "Запись"]
        ForEach(posts, id: \.self) { post in
            VStack {
                Image("postThumbnail")
                    .renderingMode(.original)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                Text(post)
            }
        }
        
    }
}

Если массив posts объявить по-другому, то ошибки не будет.

let posts = ["Запись 1", "Запись 2", "Запись 3"]

Я так понял, что он воспринимает эти строки, как ключи массива что ли... И, так как строки совпадали, появлялась ошибка. Как исправить, чтобы не было ошибок при использовании одинаковых значений массива?


Ответы (1 шт):

Автор решения: VAndrJ

Да, проблема именно в том, что id для ForEach должны быть уникальными. В данном же случае они повторяются.

Поэтому можно сделать структуру-обертку и ее использовать:

struct RepeatsAvailableString {
    let id: UUID().uuidString
    let rawValue: String
}

let posts: [RepeatsAvailableString] = [RepeatsAvailableString(rawValue: "Запись"), RepeatsAvailableString(rawValue: "Запись"), RepeatsAvailableString(rawValue: "Запись")]
ForEach(posts, id: \.self.id) { post in
    VStack {
        Text(post.rawValue)
    }
}

Ну и можно немного улучшить ее для упрощения использования:

struct RepeatsAvailableString: Identifiable, RawRepresentable, ExpressibleByStringLiteral, Hashable {
    typealias RawValue = String
    typealias StringLiteralType = String
    
    let id = UUID().uuidString
    let rawValue: String
    
    init?(rawValue: String) {
        self.rawValue = rawValue
    }
    
    init(stringLiteral value: String) {
        self.rawValue = value
    }
}
    
let posts: [RepeatsAvailableString] = ["Запись", "Запись", "Запись"]
ForEach(posts) { post in
    VStack {
        Text(post.rawValue)
    }
}
→ Ссылка