在SwiftUI中,如何响应“上的更改”@已出版的vars“*a“的*外部;“视图”;
假设我有以下在SwiftUI中,如何响应“上的更改”@已出版的vars“*a“的*外部;“视图”;,swiftui,Swiftui,假设我有以下ObservableObject,它每秒生成一个随机字符串: import SwiftUI class SomeObservable: ObservableObject { @Published var information: String = "" init() { Timer.scheduledTimer( timeInterval: 1.0, target: self,
ObservableObject
,它每秒生成一个随机字符串:
import SwiftUI
class SomeObservable: ObservableObject {
@Published var information: String = ""
init() {
Timer.scheduledTimer(
timeInterval: 1.0,
target: self,
selector: #selector(updateInformation),
userInfo: nil,
repeats: true
).fire()
}
@objc func updateInformation() {
information = String("RANDOM_INFO".shuffled().prefix(5))
}
}
以及一个视图
,它观察到:
struct SomeView: View {
@ObservedObject var observable: SomeObservable
var body: some View {
Text(observable.information)
}
}
上述操作将按预期进行。视图
在可观察对象
更改时会重新绘制自身:
现在回答问题:
我如何在一个“纯”结构中执行同样的操作(比如调用一个函数),该结构也观察相同的可观察对象
?“纯”指的是不符合视图的东西:
struct SomeStruct {
@ObservedObject var observable: SomeObservable
// How to call this function when "observable" changes?
func doSomethingWhenObservableChanges() {
print("Triggered!")
}
}
(它也可以是类
,只要它能够对可观察对象的变化做出反应。)
这在概念上似乎很容易,但我显然遗漏了一些东西
(注意:我使用的是Xcode 11,beta 6。)
更新(面向未来读者)(粘贴在操场上)
以下是一个可能的解决方案,基于@Fabian提供的令人敬畏的答案:
import SwiftUI
import Combine
import PlaygroundSupport
class SomeObservable: ObservableObject {
@Published var information: String = "" // Will be automagically consumed by `Views`.
let updatePublisher = PassthroughSubject<Void, Never>() // Can be consumed by other classes / objects.
// Added here only to test the whole thing.
var someObserverClass: SomeObserverClass?
init() {
// Randomly change the information each second.
Timer.scheduledTimer(
timeInterval: 1.0,
target: self,
selector: #selector(updateInformation),
userInfo: nil,
repeats: true
).fire() }
@objc func updateInformation() {
// For testing purposes only.
if someObserverClass == nil { someObserverClass = SomeObserverClass(observable: self) }
// `Views` will detect this right away.
information = String("RANDOM_INFO".shuffled().prefix(5))
// "Manually" sending updates, so other classes / objects can be notified.
updatePublisher.send()
}
}
class SomeObserverClass {
@ObservedObject var observable: SomeObservable
// More on AnyCancellable on: apple-reference-documentation://hs-NDfw7su
var cancellable: AnyCancellable?
init(observable: SomeObservable) {
self.observable = observable
// `sink`: Attaches a subscriber with closure-based behavior.
cancellable = observable.updatePublisher
.print() // Prints all publishing events.
.sink(receiveValue: { [weak self] _ in
guard let self = self else { return }
self.doSomethingWhenObservableChanges()
})
}
func doSomethingWhenObservableChanges() {
print(observable.information)
}
}
let observable = SomeObservable()
struct SomeObserverView: View {
@ObservedObject var observable: SomeObservable
var body: some View {
Text(observable.information)
}
}
PlaygroundPage.current.setLiveView(SomeObserverView(observable: observable))
导入快捷界面
进口联合收割机
导入PlaygroundSupport
类SomeObservable:ObservableObject{
@已发布的变量信息:String=”“//将由“视图”自动使用。
让updatePublisher=PassthroughSubject()//可以被其他类/对象使用。
//添加到这里只是为了测试整个过程。
var someObserverClass:someObserverClass?
init(){
//每秒随机更改信息。
Timer.scheduledTimer(
时间间隔:1.0,
目标:自我,
选择器:#选择器(更新信息),
userInfo:nil,
重复:对
).fire()}
@objc func更新信息(){
//仅用于测试目的。
如果someObserverClass==nil{someObserverClass=someObserverClass(可观察:self)}
//“视图”将立即检测到这一点。
信息=字符串(“随机信息”.shuffled().前缀(5))
//“手动”发送更新,以便通知其他类/对象。
updatePublisher.send()
}
}
类someobserver类{
@观察到的对象var可观察到的:一些可观察到的
//更多关于任何可取消的内容,请访问:apple参考文档mentation://hs-NDfw7su
var可取消:任何可取消?
init(可观察的:一些可观察的){
可观察的
//`sink`:使用基于闭包的行为附加订阅服务器。
可取消=可观察。更新发布器
.print()//打印所有发布事件。
.sink(接收值:{[weak self]\uuIn
guard let self=self-else{return}
self.doSomethinghenobservableChanges()
})
}
func dosomethinghenobservableChanges(){
打印(可观察信息)
}
}
let observable=SomeObservable()
结构SomeObserverView:View{
@观察到的对象var可观察到的:一些可观察到的
var body:一些观点{
文本(可观察信息)
}
}
PlaygroundPage.current.setLiveView(SomeObserverView(可观察:可观察))
结果
(注意:必须运行应用程序才能检查控制台输出。)旧方法是使用您注册的回调。较新的方法是使用Combine
框架来创建发布服务器,您可以为其注册进一步的处理,或者在本例中是一个sink
,每次源发布服务器发送消息时都会调用它。此处的发布者不发送任何内容,因此属于
类型
计时器发布器
要从计时器获取发布服务器,可以直接通过Combine
或通过PassthroughSubject()
创建通用发布服务器,注册消息并通过publisher.send()
在计时器回调中发送消息。该示例有两种变体
ObjectWillChange发布者
每个observeObject
都有一个.objectWillChange
发布服务器,您可以为其注册一个接收器
,就像您为计时器发布服务器
注册一样。每次调用它或每次@Published
变量更改时都应该调用它。但是请注意,这是在更改之前调用的,而不是在更改之后调用的。(DispatchQueue.main.async{}
在接收器内部,以在更改完成后作出反应)
登记
每个接收器调用都会创建一个必须存储的anycancelable
,通常存储在sink
应该具有相同生存期的对象中。一旦取消构造可取消项(或调用其上的.cancel()
),就不会再次调用接收器
import SwiftUI
import Combine
struct ReceiveOutsideView: View {
#if swift(>=5.3)
@StateObject var observable: SomeObservable = SomeObservable()
#else
@ObservedObject var observable: SomeObservable = SomeObservable()
#endif
var body: some View {
Text(observable.information)
.onReceive(observable.publisher) {
print("Updated from Timer.publish")
}
.onReceive(observable.updatePublisher) {
print("Updated from updateInformation()")
}
}
}
class SomeObservable: ObservableObject {
@Published var information: String = ""
var publisher: AnyPublisher<Void, Never>! = nil
init() {
publisher = Timer.publish(every: 1.0, on: RunLoop.main, in: .common).autoconnect().map{_ in
print("Updating information")
//self.information = String("RANDOM_INFO".shuffled().prefix(5))
}.eraseToAnyPublisher()
Timer.scheduledTimer(
timeInterval: 1.0,
target: self,
selector: #selector(updateInformation),
userInfo: nil,
repeats: true
).fire()
}
let updatePublisher = PassthroughSubject<Void, Never>()
@objc func updateInformation() {
information = String("RANDOM_INFO".shuffled().prefix(5))
updatePublisher.send()
}
}
class SomeClass {
@ObservedObject var observable: SomeObservable
var cancellable: AnyCancellable?
init(observable: SomeObservable) {
self.observable = observable
cancellable = observable.publisher.sink{ [weak self] in
guard let self = self else {
return
}
self.doSomethingWhenObservableChanges() // Must be a class to access self here.
}
}
// How to call this function when "observable" changes?
func doSomethingWhenObservableChanges() {
print("Triggered!")
}
}
导入快捷界面
进口联合收割机
结构接收外部视图:视图{
#如果swift(>=5.3)
@StateObject变量可观测:SomeObservable=SomeObservable()
#否则
@ObservedObject var observable:SomeObservable=SomeObservable()
#恩迪夫
var body:一些观点{
文本(可观察信息)
.onReceive(observable.publisher){
打印(“从Timer.publish更新”)
}
.onReceive(observable.updatePublisher){
打印(“从updateInformation()更新”)
}
}
}
类SomeObservable:ObservableObject{
@已发布的变量信息:String=“”
var publisher:AnyPublisher!=nil
init(){
publisher=Timer.publish(every:1.0,on:RunLoop.main,in:.common).autoconnect().map{in
打印(“更新信息”)
//self.information=String(“RANDOM_INFO”.shuffled()。前缀(5))
}.删除任何发布者()
Timer.scheduledTimer(
时间间隔:1.0,
目标:自我,
选择器:#选择器(更新信息),
userInfo:nil,
重复:对
).火灾
}
让updatePublisher=PassthroughSubject()
@objc func更新信息(){
英富曼集团