强制发布者发布更新?
Force publisher to publish an update?
在我的 ViewModel
的 init()
中,我有 2 个订阅者。
- 第一个订阅了
DataProvider()
内下载的数据,并用结果更新 downloadedData
。这会进行 API 调用,通常需要几秒钟才能发布数据。
- 第二个订阅
$savedData
,然后仅使用 savedData
AND 中包含的数据更新 filteredData
数组downloadedData
.
问题是 downloadedData
需要时间下载,而 savedData
是即时的(它实际上在 Core Data 中)。下载后,我想强制更新上面的第二个观察者 ($savedData
) 以相应地更新 filteredData
。
有没有办法手动强制发布者发布一个值?在 ObservedObjects 上,我们可以调用 objectWillChange.send()
但有没有类似的东西我可以调用 $savedData
?
免责声明:这是我的应用程序的超级简化版本。请不要包含更改层次结构的答案。我还意识到我可以在 $allCoins 上添加另一个发布者来模仿 $savedData 上的发布者,但我宁愿强制更新 $savedData。谢谢!
import SwiftUI
struct TestView: View {
@StateObject var vm = ViewModel()
var body: some View {
VStack {
ForEach(vm.filteredData, id: \.self) { user in
Text(user)
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
import Combine
class ViewModel: ObservableObject {
@Published var downloadedData: [String] = []
@Published var savedData: [String] = []
@Published var filteredData: [String] = []
var cancellables = Set<AnyCancellable>()
@Published var provider = DataProvider()
init() {
// WHEN THIS GETS PUBLISHED...
// CAN I FORCE A PUBLISH / UPDATE TO savedData?
provider.$data
.assign(to: \.downloadedData, on: self)
// here?
.store(in: &cancellables)
$savedData
.map { (saved) -> [String] in
return saved.map { (savedItem) -> String in
return self.downloadedData.contains(savedItem) ? savedItem : "NO"
}
}
.assign(to: \.filteredData, on: self)
.store(in: &cancellables)
getSavedData()
}
func getSavedData() {
savedData = ["ONE", "TWO"]
}
}
class DataProvider: ObservableObject {
@Published var data: [String] = []
init() {
getData()
}
func getData() {
// simulating api call
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.data.append(contentsOf: ["ONE", "TWO"])
}
}
}
您可以订阅下载的数据并将其分配给已保存的数据:
$downloadedData
.assign(to: \.savedData, on: self)
.store(in: &cancellables)
请参考下面的link因为使用assign(to: on:)
当self
作为参数传递时会导致内存泄漏
https://forums.swift.org/t/does-assign-to-produce-memory-leaks/29546/11
您的其他订阅也以 self
作为参数调用 assign(to: on:)
,最好在 link 中实施解决方案,因为它在整个过程中都解决了这个问题整个应用程序。
您可能以错误的方式思考问题。
首先,让我们弄清楚术语。您正在 订阅 您的 init
中的 2 个发布者。每当它们各自的 属性 发生变化时,这两个发布者都会发出一个值。
您似乎想要做的是在 savedData
或 downloadedData
发生变化时更新 filteredData
。因此,您不应该“强制更新”,而应该订阅那种在您需要时发出您想要的内容的发布者。您可以使用 CombineLatest
实现此目的:
$savedData.combineLatest(provider.$data)
.map { (saved, downloaded) in
//...
}
.sink { [weak self] value in
self?.filteredData = value
}
.store(in: &cancellables)
(不要使用 assign
- 它会创建对 self
的强引用;请改用 sink
和 weak self
)
在我的 ViewModel
的 init()
中,我有 2 个订阅者。
- 第一个订阅了
DataProvider()
内下载的数据,并用结果更新downloadedData
。这会进行 API 调用,通常需要几秒钟才能发布数据。 - 第二个订阅
$savedData
,然后仅使用savedData
AND 中包含的数据更新filteredData
数组downloadedData
.
问题是 downloadedData
需要时间下载,而 savedData
是即时的(它实际上在 Core Data 中)。下载后,我想强制更新上面的第二个观察者 ($savedData
) 以相应地更新 filteredData
。
有没有办法手动强制发布者发布一个值?在 ObservedObjects 上,我们可以调用 objectWillChange.send()
但有没有类似的东西我可以调用 $savedData
?
免责声明:这是我的应用程序的超级简化版本。请不要包含更改层次结构的答案。我还意识到我可以在 $allCoins 上添加另一个发布者来模仿 $savedData 上的发布者,但我宁愿强制更新 $savedData。谢谢!
import SwiftUI
struct TestView: View {
@StateObject var vm = ViewModel()
var body: some View {
VStack {
ForEach(vm.filteredData, id: \.self) { user in
Text(user)
}
}
}
}
struct TestView_Previews: PreviewProvider {
static var previews: some View {
TestView()
}
}
import Combine
class ViewModel: ObservableObject {
@Published var downloadedData: [String] = []
@Published var savedData: [String] = []
@Published var filteredData: [String] = []
var cancellables = Set<AnyCancellable>()
@Published var provider = DataProvider()
init() {
// WHEN THIS GETS PUBLISHED...
// CAN I FORCE A PUBLISH / UPDATE TO savedData?
provider.$data
.assign(to: \.downloadedData, on: self)
// here?
.store(in: &cancellables)
$savedData
.map { (saved) -> [String] in
return saved.map { (savedItem) -> String in
return self.downloadedData.contains(savedItem) ? savedItem : "NO"
}
}
.assign(to: \.filteredData, on: self)
.store(in: &cancellables)
getSavedData()
}
func getSavedData() {
savedData = ["ONE", "TWO"]
}
}
class DataProvider: ObservableObject {
@Published var data: [String] = []
init() {
getData()
}
func getData() {
// simulating api call
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.data.append(contentsOf: ["ONE", "TWO"])
}
}
}
您可以订阅下载的数据并将其分配给已保存的数据:
$downloadedData
.assign(to: \.savedData, on: self)
.store(in: &cancellables)
请参考下面的link因为使用assign(to: on:)
当self
作为参数传递时会导致内存泄漏
https://forums.swift.org/t/does-assign-to-produce-memory-leaks/29546/11
您的其他订阅也以 self
作为参数调用 assign(to: on:)
,最好在 link 中实施解决方案,因为它在整个过程中都解决了这个问题整个应用程序。
您可能以错误的方式思考问题。
首先,让我们弄清楚术语。您正在 订阅 您的 init
中的 2 个发布者。每当它们各自的 属性 发生变化时,这两个发布者都会发出一个值。
您似乎想要做的是在 savedData
或 downloadedData
发生变化时更新 filteredData
。因此,您不应该“强制更新”,而应该订阅那种在您需要时发出您想要的内容的发布者。您可以使用 CombineLatest
实现此目的:
$savedData.combineLatest(provider.$data)
.map { (saved, downloaded) in
//...
}
.sink { [weak self] value in
self?.filteredData = value
}
.store(in: &cancellables)
(不要使用 assign
- 它会创建对 self
的强引用;请改用 sink
和 weak self
)