Сбой вложенного ForEach внутри LazyHStack

У меня есть два вложенных s внутри LazyHStack

      LazyHStack {
    ForEach(items) { item in
        ForEach(item.urls, id: \.self) {
            Text($0.absoluteString)
        }
    }
}

Этот фрагмент компилируется, но сразу вылетает со следующей ошибкой

Неустранимая ошибка: каждый элемент макета может возникнуть только один раз: файл SwiftUI, строка 0

Я читал в Интернете, что это может быть связано с неправильным различением элементов коллекции, даже если все они идентифицируются. В моем случае items во внешнем все идентифицируемы, в то время как внутренние ForEach проходит через массив необязательных URL?объекты. Я пытался сделать URL можно идентифицировать с помощью своей абсолютной строки (которая, я думаю, должна быть уникальной), но это не сработало.

      extension URL: Identifiable {
    var id: String? { absoluteString } 
}

Я должен добавить, что тот же фрагмент кода отлично работает со стандартным HStack. Как я могу решить эту проблему?

2 ответа

Вам решать, как именно будет построен пользовательский интерфейс, но этот ответ создает горизонтально прокручиваемый список URL-адресов, которые вертикально уложены как часть каждого элемента.

Рабочий код:

      ScrollView(.horizontal) {
    LazyHStack {
        ForEach(items) { item in
            VStack {
                ForEach(item.urls) {
                    Text($0.absoluteString)
                }
            }
        }
    }
}

Изменения:

  1. Завернутый в ScrollView, чтобы элементы за пределами экрана можно было прокрутить для просмотра.
  2. Между s вставлен a, чтобы определить макет для каждого item.
  3. Удаленный id: \.selfсо второго, потому что вы уже создали кастом для URL. Либо используйте id: \.id или не включайте id параметр в ForEach.

Результат:

Другая возможность - установить уникальный идентификатор для каждого элемента. В принципе, если несколько URL-адресов одинаковы (следовательно, имеют одинаковый идентификатор), то LazyHStackпроблема в том, что не все идентификаторы уникальны. Ссылка на аналогичный ответ здесь . Это альтернативное исправление, которое не требует VStack между:

      Text($0.absoluteString)
    .id(item.id.uuidString + ($0.id ?? ""))

Изменить для поддержки дополнительных URL-адресов

Структура данных (разница только в URL был заменен на URLItem поэтому мы можем хранить необязательное значение):

      struct Item: Identifiable {
    let id = UUID()
    let urls: [URLItem]
}

struct URLItem: Identifiable {
    let id = UUID()
    let url: URL?
    
    init(_ url: URL?) {
        self.url = url
    }
}

Новые данные примера:

      let items: [Item] = [
    Item(urls: [
        URLItem(URL(string: "https://www.google.com")), URLItem(URL(string: "https://www.stackoverflow.com"))
    ]),
    Item(urls: [
        URLItem(URL(string: "https://www.stackoverflow.com")), URLItem(URL(string: ""))
    ])
]

Это означает, что теперь мы можем иметь Identifiableнеобязательные URL-адреса. Теперь код должен выглядеть так:

      ForEach(item.urls) {
    if let url = $0.url {
        Text(url.absoluteString)
            .id($0.id)
    } else {
        Text("Bad URL")
            .id($0.id)
    }
}

Теперь вы можете заниматься своими делами, когда $0.url является nil.

Он работает, у вас была ошибка в коде:

например, вы должны использовать selfв вашем расширении

также вы использовали 2 ForEach внутри вместе без причины, я бы сказал, плохое кодирование, я не собираюсь советовать использовать 2 ForEach внутри вместе, это сбивает систему и ваше приложение, используйте 1 ForEach! Однако вот ваш ответ:



       struct ContentView: View {
    
    @State private var items: [[URL]] = [[URL(string: "www.apple.com")!, URL(string: "www.amazon.com")!, URL(string: "www.google.com")!], [URL(string: "www.Tesla.com")!]]

    var body: some View {

        LazyHStack {
            
            ForEach(items, id: \.self) { item in
                
                ForEach(item) { url in
                    Text(url.absoluteString)
                }
                
            }
            
        }
        
        
    }
    
}

extension URL: Identifiable {
    public var id: String { self.absoluteString }
}
Другие вопросы по тегам