【问题标题】:SWIFTUI: Create Class with Array property - witch conform to 'ObservableObject'. Class! NOT structSWIFTUI:使用 Array 属性创建类 - 符合“ObservableObject”。班级!非结构
【发布时间】:2021-11-01 03:19:27
【问题描述】:

我需要创建符合 ObservableObject 协议的类的 Array 属性。因为我要将它与过滤器、排序等一起使用 - 从表中选择记录以显示在列表视图中

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 在这种情况下应该可以工作。
  • 或者添加一个保存数组的视图模型类
  • 数组不符合ObservableObjects 你必须一次观察单个项目与整个数组
  • @FetchRequest 是此类集合的一个示例 - 一个持有人中的一些项目 - 每个项目的更改都显示在持有人中
  • 要查看@FetchRequest 中各个项目的更改,请将它们包装在@ObservedObject 中。您不会自己看到更改

标签: arrays swift swiftui observableobject


【解决方案1】:

如果我正确理解您的问题,您的array 的项目是类。您可以将数组声明为 @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)
                    }
                }
            }
        }
    }
}

如您所见,“首先更改”按钮实际上更改了“记录”的“分数”,但不显示此修改。

如果您希望“发布”对数组每个元素的更改,则必须分几个步骤进行:

  1. 让您的Records 可观察:
class Record: ObservableObject, Identifiable {
    let id = UUID()
    @Published var score: Int
    init(_ score: Int) {
        self.score = score
    }
}
  1. 将数组包装在 ObservableObject 中:
class RecordStore: ObservableObject {
    @Published var records: [Record] = (1 ... 5).map(Record.init)

  1. 订阅数组每个元素的变化
    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()
            }
    }
}

还有视图:

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)
                    }
                }
            }
        }
    }
}

【讨论】:

  • 谢谢。这是一个正确的方法。我将根据我的设计对其进行调整。为模拟数组等添加订阅
  • @Alex778801:不客气。我看到您是 SO 新手:如果您认为某个答案解决了您的问题,请将其标记为“已接受”by clicking the green check mark。你也可以vote up answers that are helpful and well-researched
  • @Published var records: [Record] = (1 ... 5).map(Record.init) { didSet { subscribeToChanges() ///
  • @Alex :不为records 提供默认值,并在init 中初始化该值。 @Published var records: [Record] { didSet { subscribeToChanges() } }init(records [Record]) { self.records = records }
  • 我想调试 RecordStore() 类。如何在 [Record] 数组和每个 Record 属性中接收所有更改 objectWillChange.send() - 并将其打印到控制台?并显示属性/更改的值 - 如果可能的话。谢谢
猜你喜欢
  • 2021-01-25
  • 2022-01-12
  • 2020-04-19
  • 2021-02-27
  • 2020-10-25
  • 1970-01-01
  • 1970-01-01
  • 2018-01-13
  • 1970-01-01
相关资源
最近更新 更多