1

我有一个符合“ObservableObject”协议的类(WatchlistClass),它包含一个@Published var(监视列表)。反过来,var 包含一系列股票和一些信息([StockInformation]),它应该用当前的股票价格和东西更新我的视图(WatchlistView)。该部分工作得很好,但是该类应该访问视图中的@StateObject 以更改数据。直接在类中访问它是行不通的,因为它不会从@StateObject 读取数据。我尝试直接访问视图中的@StateObject,但这也创建了一个具有空数组的类的新实例。在 @Published var 上使用“静态”会引发错误。我不能,为了我的一生,弄清楚如何在视图中直接访问 @StateObject 以读取和修改它所保存的数据。任何帮助,将不胜感激。

class WatchlistClass: ObservableObject {
    static let shared = WatchlistClass()
    
    @Published var watchlist: [StockInformation] = []
    
    struct StockInformation: Identifiable {
        ...
    }
    

    func WatchlistTasksGetFundamentalsDelegate(string: String) {
        ...            
            DispatchQueue.main.async {
                self.watchlist.append(stockInformation) // This works and updates the view as expected
            }
        ...
    }


    private let timer = Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true) { _ in
        if self.watchlist.isEmpty == false { // This does not work
            ...
    }
}
struct WatchlistView: View {
    @StateObject var watchlistClass = WatchlistClass()
    ...
}
4

2 回答 2

1

使用单例模式时,您通常希望init将对象声明为私有,因此您确定只能创建它的一个实例。

然后,要访问该单例版本,您将使用WatchlistClass.shared

class WatchlistClass: ObservableObject {
    static let shared = WatchlistClass()
    
    @Published var watchlist: [StockInformation] = []
    
    struct StockInformation: Identifiable {
        //...
    }
    
    private init() { }
}

struct WatchlistView: View {
    @StateObject var watchlistClass = WatchlistClass.shared
    
    var body: some View {
        //...
    }
}

就您的 而言Timer,了解更多关于它在此处服务的目的的信息会很有帮助。例如,如果它只是检查watchlist对它做出反应,我的建议是使用Combineto watch 它而不是Timer.

如果单例版本的目的只是尝试访问Timer并使其能够访问数组,那么像这样的模式可能会更好:

import Combine

class WatchlistClass: ObservableObject {
    
    @Published var watchlist: [StockInformation] = []
    
    private var cancellable : AnyCancellable?
    
    struct StockInformation: Identifiable {
        var id = UUID()
        //...
    }
    
    public init() {
        cancellable = Timer.publish(every: 1, on: .main, in: .default)
            .autoconnect()
            .receive(on: RunLoop.main)
            .sink { _ in
                if !self.watchlist.isEmpty {
                    
                }
            }
    }
}

struct WatchlistView: View {
    @StateObject var watchlistClass = WatchlistClass()
    
    var body: some View {
        Text("Hello, world!")
    }
}

这将创建Timeroninit并授予它访问实例watchlist数组的权限。

于 2021-11-06T03:52:58.363 回答
1

Yourtimer是一个实例变量,但它的闭包不是该类的实例并且没有self.

您将不得不做一些事情将“自我”放入计时器块的范围内。一种方法是在实例的成员函数中创建计时器:

private func makeTimer() -> Timer {
    return Timer.scheduledTimer(withTimeInterval: 4.0, repeats: true) { [weak self] _ in
        if let empty = self?.watchlist.isEmpty,
            empty == false {
        }
    }
}

当您调用 makeTimer() 您的代码将在实例的上下文中执行。它将有权访问self.

请注意,我已经更改了您的块,使其捕获的self“弱”,因为计时器可能存在于对象的生命周期之外,因此您必须主动应对这种可能性。

您可以从初始化程序调用 makeTimer 。

于 2021-11-06T03:57:50.753 回答