Соответствие массива идентифицируемому в SwiftUI

#ios #swift #swiftui #protocols #identifiable

Вопрос:

У меня есть небольшой вопрос о соответствии Identifiable SwiftUI требованиям .

Бывают ситуации, когда от нас требуется, чтобы мы соответствовали заданному типу MyType Identifiable .

Но я сталкиваюсь со случаем, когда от меня требуется, чтобы [MyType] (массив MyType) соответствовал Identifiable .

У меня уже есть свой тип, соответствующий Identifiable . Что я должен сделать, чтобы также соответствовать [MyType] Identifiable ?

Ответ №1:

Я предлагаю встроить [MyType] в структуру, а затем привести структуру в соответствие Identifiable . Что-то вроде этого:

 struct MyType: Identifiable {
    let id = UUID()
}
struct Container: Identifiable {
    let id = UUID()
    var myTypes = [MyType]()
}
 

Использование:

 struct ContentView: View {
    let containers = [
        Container(myTypes: [
            MyType(),
            MyType()
        ]),
        Container(myTypes: [
            MyType(),
            MyType(),
            MyType()
        ])
    ]
    
    var body: some View {

        /// no need for `id: .self`
        ForEach(containers) { container in
            ...
        }
    }
}
 

Ответ №2:

Вы можете написать расширение, чтобы соответствовать Array Identifiable .

Поскольку расширения не могут содержать сохраненные свойства, а также потому , что имеет смысл, чтобы два «одинаковых» массива также имели одно и то же id , вам нужно будет вычислить их на id основе содержимого массива.

Самый простой подход здесь заключается в том, можете ли вы соответствовать своему типу Hashable :

 extension MyType: Hashable {}
 

Это также позволяет [MyType] соответствовать Hashable , и поскольку id может быть любым Hashable , вы можете использовать сам массив как свой собственный id :

 extension Array: Identifiable where Element: Hashable {
   public var id: Self { self }
}
 

Или, если хотите, id это может быть Int :

 extension Array: Identifiable where Element: Hashable {
   public var id: Int { self.hashValue }
}
 

Конечно, вы можете сделать это только для своего собственного типа where Element == MyType , но этот тип должен быть public таким .

Комментарии:

1. @New_Dev. Прежде чем увидеть этот ответ, я на самом деле попробовал его, основываясь на вашем предложении в комментарии, который вы ранее написали. Но я потерпел неудачу. С этой новой идеей использования хэширования это может сработать, но я должен сказать, что мне не очень нравится идея «использовать сам массив в качестве собственного идентификатора».

2. @Мишель. почему нет? Identifiable просто нужно Hashable … так что под прикрытием он просто использует хэш.

3. @Michel, Если вам это неудобно, вы можете сделать id an Int , используя значение хэша напрямую — см. Обновленный ответ

4. ДА. Я думаю, это тоже может сработать. Еще один интересный момент вашего предложения, вы написали «потому что имеет смысл, чтобы два массива, которые являются»одинаковыми», также имели один и тот же идентификатор». Я не уверен, что именно так должен работать идентификатор. Идентификатор должен позволять вам различать n-й элемент и m-й элемент независимо от того, равны они или нет. Скажи мне, если я ошибаюсь.

5. @Michel — Я думаю, это зависит от того, чего вы хотите достичь и как вы хотите относиться к «равным» объектам. Это влияет на анимацию вставки и удаления в списке. Если вам нужно, чтобы каждый объект был уникальным, то вы используете что-то вроде UUID . Или вы можете использовать индекс объекта в массиве в качестве его идентификатора (но тогда объект не обязательно должен быть Identifiable ).