当用户更改全局对象时重新初始化组合发布者
Reinitialize Combine Publishers When User Changes Global Object
我有一个 Core Data 发布器,目前运行良好。我有一个 Workspace
实体和一个 Project
实体。我使用以下发布者获取给定工作区的所有项目:
class ProjectModel: ObservableObject {
@Published var projects = [Project]()
private var cancellableSet: Set<AnyCancellable> = []
init(){
CoreDataPublisher(request: Project.getAllProjects(), context: PersistenceController.shared.container.viewContext)
.sink(
receiveCompletion: { print([=10=]) },
receiveValue: { [weak self] items in
self?.projects = items
})
.store(in: &cancellableSet)
}
}
提取请求 getAllProjects()
位于此处的核心数据实体扩展中,其中 NSPredicate
过滤器基于 UI 中设置的 Workspace
对象。
//Core Data Entity Extension
extension Project{
@nonobjc public class func getAllProjects() -> NSFetchRequest<Project> {
let workspace = AppState.shared.workspace as Workspace //<-- The user can change this workspace
let request = NSFetchRequest<Project>(entityName: "\(Self.self)")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Project.name, ascending: true)]
request.predicate = NSPredicate(format: "workspace = %@", workspace)
return request
}
}
此 Workspace
对象处于全局状态 class:
class AppState: ObservableObject{
static let shared = AppState()
@Published var workspace: Workspace!
init(){
//Setup the workspace for the first time
}
}
我可以成功地从我的发布者那里接收数据,并且我可以在 UI 中成功地更改全局 Workspace
。问题是在更改 Workspace
后,发布者仍然指向创建提取请求时最初设置的旧 Workspace
。
如何在 AppState
的 workspace
更改时提示 ProjectModel
重新初始化以更新发布者的状态?
在你的 ProjectModel
中,我将从 AnyCancellable
的 Set
切换到特定的,以便你可以取消它:
var cdPublisherCancellable : AnyCancellable?
我会将此发布者的设置移出 init,因为您需要再次调用它:
func setupPublisher() {
cdPublisherCancellable?.cancel()
cdPublisherCancellable = CoreDataPublisher(request:)...
}
然后,由于工作区是在您的共享 AppState 上发布的 属性,我会设置另一个发布者 link 来观看它:
var workspaceCancellable : AnyCancellable?
init() {
workspaceCancellable = AppState.shared.$workspace.sink { workspace in
setupPublisher()
}
}
通常,实现此目的的方法是在发布商上使用 flatMap
运算符。 flatMap
允许您“根据接收到的值创建一个新的发布者,然后使用该发布者的输出作为整个发布者链的输出”。
看起来像这样:
AppState.shared.$workspace.flatMap { workspace in
let request = NSFetchRequest<Project>(entityName: "\(Project.self)")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Project.name, ascending: true)]
request.predicate = NSPredicate(format: "workspace = %@", workspace)
return CoreDataPublisher(request: request, context: PersistenceController.shared.container.viewContext)
}
这为您提供了一个新发布商:
- 当
.workspace
属性 在您的应用程序状态上发生变化时,根据新的 Workspace
值 构建一个新的 CoreDataPublisher
- 使用
CoreDataPublisher
作为整个发布者流的值来源
我有一个 Core Data 发布器,目前运行良好。我有一个 Workspace
实体和一个 Project
实体。我使用以下发布者获取给定工作区的所有项目:
class ProjectModel: ObservableObject {
@Published var projects = [Project]()
private var cancellableSet: Set<AnyCancellable> = []
init(){
CoreDataPublisher(request: Project.getAllProjects(), context: PersistenceController.shared.container.viewContext)
.sink(
receiveCompletion: { print([=10=]) },
receiveValue: { [weak self] items in
self?.projects = items
})
.store(in: &cancellableSet)
}
}
提取请求 getAllProjects()
位于此处的核心数据实体扩展中,其中 NSPredicate
过滤器基于 UI 中设置的 Workspace
对象。
//Core Data Entity Extension
extension Project{
@nonobjc public class func getAllProjects() -> NSFetchRequest<Project> {
let workspace = AppState.shared.workspace as Workspace //<-- The user can change this workspace
let request = NSFetchRequest<Project>(entityName: "\(Self.self)")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Project.name, ascending: true)]
request.predicate = NSPredicate(format: "workspace = %@", workspace)
return request
}
}
此 Workspace
对象处于全局状态 class:
class AppState: ObservableObject{
static let shared = AppState()
@Published var workspace: Workspace!
init(){
//Setup the workspace for the first time
}
}
我可以成功地从我的发布者那里接收数据,并且我可以在 UI 中成功地更改全局 Workspace
。问题是在更改 Workspace
后,发布者仍然指向创建提取请求时最初设置的旧 Workspace
。
如何在 AppState
的 workspace
更改时提示 ProjectModel
重新初始化以更新发布者的状态?
在你的 ProjectModel
中,我将从 AnyCancellable
的 Set
切换到特定的,以便你可以取消它:
var cdPublisherCancellable : AnyCancellable?
我会将此发布者的设置移出 init,因为您需要再次调用它:
func setupPublisher() {
cdPublisherCancellable?.cancel()
cdPublisherCancellable = CoreDataPublisher(request:)...
}
然后,由于工作区是在您的共享 AppState 上发布的 属性,我会设置另一个发布者 link 来观看它:
var workspaceCancellable : AnyCancellable?
init() {
workspaceCancellable = AppState.shared.$workspace.sink { workspace in
setupPublisher()
}
}
通常,实现此目的的方法是在发布商上使用 flatMap
运算符。 flatMap
允许您“根据接收到的值创建一个新的发布者,然后使用该发布者的输出作为整个发布者链的输出”。
看起来像这样:
AppState.shared.$workspace.flatMap { workspace in
let request = NSFetchRequest<Project>(entityName: "\(Project.self)")
request.sortDescriptors = [NSSortDescriptor(keyPath: \Project.name, ascending: true)]
request.predicate = NSPredicate(format: "workspace = %@", workspace)
return CoreDataPublisher(request: request, context: PersistenceController.shared.container.viewContext)
}
这为您提供了一个新发布商:
- 当
.workspace
属性 在您的应用程序状态上发生变化时,根据新的Workspace
值 构建一个新的 - 使用
CoreDataPublisher
作为整个发布者流的值来源
CoreDataPublisher