我需要创建符合 ObservableObject 协议(protocol)的类的 Array 属性。因为我将把它与过滤器、排序等一起使用 - 从表中选择记录以在 ListView 中显示
class SQS_Record: NSObject, ObservableObject {
@Published final var __idx: Int = -1
}
class Project: SQS_Record {
@objc dynamic var name: String = "" { willSet { objectWillChange.send() } }
}
class SQS_Table<RecordType: SQS_Record>: ObservableObject {
@Published var records = [RecordType]()
var rcount: Int {
return records.count
}
subscript (index: Int) -> RecordType {
get {
return records[index]
}
set(item) {
records[index] = item
}
}
Let projectsTbl = SQS_Table<Project>(...)
struct ProjectsListView: View {
// This is ERROR line - below
@StateObject private var itemsList = projectsTbl.records.sorted { $0.__idx < $1.__idx }
var body: some View {
NavigationView {
List() {
// Список
ForEach (itemsList, id: \.__id) { (proj: Project) in
ProjectElement(project: proj)
}
.onMove(perform: moveItem )
.onDelete(perform: delItem )
}
…
}
错误:通用结构“StateObject”要求“[Project]”符合“ObservableObject”
最佳答案
如果我正确理解你的问题,你的数组
的项目是类。您可以将数组声明为@State
,但只有对数组本身的更改(添加、排序、删除)才会导致重新计算body
。
让我们尝试一下:
struct ArrayOfObservableObjects: View {
@State private var store = (1 ... 5).map(Record.init)
var body: some View {
NavigationView {
List(store) { record in
Text(record.score.description)
}
.toolbar {
HStack {
Button("Shuffle") {
store.shuffle()
}
Button("Change First") {
store.first?.score = 666
}
Button("Add") {
store.insert(Record(store.count + 1), at: 0)
}
}
}
}
}
}
正如您所看到的,“更改第一”按钮实际上更改了“记录”的“分数”,但这种修改不会显示。
如果您希望“发布”对数组每个元素的更改,则必须执行以下几个步骤:
- 使您的
记录
可观察:
class Record: ObservableObject, Identifiable {
let id = UUID()
@Published var score: Int
init(_ score: Int) {
self.score = score
}
}
- 将数组包装在 ObservableObject 中:
class RecordStore: ObservableObject {
@Published var records: [Record] = (1 ... 5).map(Record.init)
- 订阅数组每个元素的更改
private var c: AnyCancellable?
init() {
subscribeToChanges()
}
func subscribeToChanges() {
c = records
.publisher
.flatMap { record in record.objectWillChange }
.sink { [weak self] in
self?.objectWillChange.send()
}
}
}
它有效。但是缺少了一些东西(如果我们添加一个新元素,它将不会被观察到)。所以要完成:
class RecordStore: ObservableObject {
@Published var records: [Record] = (1 ... 5).map(Record.init) {
didSet {
subscribeToChanges() ///<<< HERE
}
}
private var c: AnyCancellable?
init() {
subscribeToChanges()
}
func subscribeToChanges() {
c = records
.publisher
.flatMap { record in record.objectWillChange }
.sink { [weak self] in
self?.objectWillChange.send()
}
}
}
和 View :
import Combine
import SwiftUI
struct ArrayOfObservableObjects: View {
@StateObject var store = RecordStore()
var body: some View {
NavigationView {
List(store.records) { record in
Text(record.score.description)
}
.toolbar {
HStack {
Button("Shuffle") {
store.records.shuffle()
}
Button("Change First") {
store.records.first?.score = 666
}
Button("Add") {
store.records.insert(Record(store.records.count + 1), at: 0)
}
}
}
}
}
}
关于arrays - SWIFTUI:使用 Array 属性创建类 - 符合 'ObservableObject' 。类(class)!不是结构体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69033796/