Я создал тривиальный проект, чтобы попытаться лучше понять это. Код ниже.
У меня есть источник данных (DataSource
), который содержит @Published
массив MyObject
элементов. MyObject
содержит одну строку. Нажатие кнопки в пользовательском интерфейсе вызывает немедленное обновление одного из экземпляров MyObject
, плюс включает таймер для обновления второго экземпляра через несколько секунд.
Если MyObject
- это структура, все работает как Я полагаю, это должно быть. Но если MyObject
- это класс, тогда refre sh не срабатывает.
Я ожидаю, что изменение значения структуры приведет к размещению измененного экземпляра в массиве, что приведет к возникновению цепочки обновления. Однако, если MyObject
является классом, при изменении строки в ссылочном типе в массиве остается тот же экземпляр. Array не понимает, что произошло изменение, поэтому не упоминает об этом в моем DataSource
. Обновление пользовательского интерфейса не происходит.
Итак, возникает вопрос - что нужно сделать, чтобы пользовательский интерфейс обновлялся при изменении свойства класса MyObject
? Я попытался сделать MyObject
an ObservableObject
и добавить некоторые didchange.send()
инструкции, но все безуспешно (я считаю, что сейчас они излишни в любом случае).
Может ли кто-нибудь сказать мне, если это возможно, и как нужно изменить приведенный ниже код, чтобы это стало возможным? И если у кого-то возникает соблазн спросить, почему я просто не использую структуры, причина в том, что в моем реальном проекте я уже пробовал это делать. Однако я использую коллекции типов данных, которые изменяются при закрытии (параллельная обработка каждого элемента в коллекции) и других обручах, через которые можно перейти. Я попытался переписать их как структуры, но столкнулся с множеством проблем.
import Foundation
import SwiftUI
struct ContentView: View
{
@ObservedObject var source = DataSource()
var body: some View
{
VStack
{
ForEach(0..<5)
{i in
HelloView(displayedString: self.source.results[i].label)
}
Button(action: {self.source.change()})
{
Text("Change me")
}
}
}
}
struct HelloView: View
{
var displayedString: String
var body: some View
{
Text("\(displayedString)")
}
}
class MyObject // Works if declared as a Struct
{
init(label: String)
{
self.label = label
}
var label: String
}
class DataSource: ObservableObject
{
@Published var results = [MyObject](repeating: MyObject(label: "test"), count: 5)
func change()
{
print("I've changed")
results[3].label = "sooner"
_ = Timer.scheduledTimer(withTimeInterval: 2, repeats: false, block: {_ in self.results[1].label = "Or later"})
}
}
struct ContentView_Previews: PreviewProvider
{
static var previews: some View
{
ContentView()
}
}