在SwiftUI中的@StateObjects之间传递数据

a0x5cqrl  于 2022-12-22  发布在  Swift
关注(0)|答案(2)|浏览(124)

在搜索了文档并阅读this基本上没有答案的问题之后,我仍然不知道如何在SwiftUI中将@Published var从类A传递到类B
我不确定我是否从根本上误解了什么,因为在我看来,下面的用例非常简单:假设我们有两个“视图模型”或“控制器”
1.位置管理器
1.发布管理器
LocationManager有一个当前位置,而PostManager -完全独立-负责获取一些帖子,然后将其存储在属性“posts”中。假设这种获取是基于位置进行的,因此只有位置与当前位置有特定关系的帖子才会被获取。通过将两个管理器分开,所有的逻辑(和事实的来源)都被整齐地组织起来,并且不直接存在于任何视图中。2假设这两个类都作为@StateObject存在于视图中。3 PostManager如何总是有一个最新版本的位置来获取帖子(例如周期性地,没有来自任何视图的任何输入)?
当然,正如链接问题中的一位评论者所建议的那样,可以使用UserDefaults来实现这一点,但我觉得这是一种变通方法,而不是最先进的实现。
代码示例

import Foundation
import SwiftUI

class LocationManager: ObservableObject {
    
    @Published var location: [Double] = []
    
    init() {
        // running stuff to keep location up to date
    }
}

class PostManager: ObservableObject {
    
    @Published var posts: [LocationPost] = []
    
    init() {
        // fetching posts based on location in LocationManager instance <- but how do we always have this information
    }
}

class LocationPost {
    var text: String = ""
    var coordinates: [Double] = []
    
    convenience init(coordinates: [Double] = [], test: String? = nil) {
        self.init()
        self.coordinates = coordinates
        self.text = text
    }
}
0s7z1bwu

0s7z1bwu1#

@Published Property Wrapper实际上是在您的属性上 Package 一个合并Publisher,您可以使用订阅它,以便在它更改时获得更新。
要做到这一点,您有几个选项,您可以使用更适合您的用例的选项。

  • LocationManager传递给PostManager,以便它订阅自己的更改,您可以直接在init上完成此操作,也可以使用其他方法。
  • PostManager传递到LocationManager
  • 从持有或引用它们的类或视图中将一个订阅到另一个。
  • 等等。

示例1

从外部类或视图订阅

var cancellable: AnyCancellable? // hold a reference to it

cancellable = locationManager.$location.sink() { location in
    postManager.updateLocation(location)
}

// inside PostManager
func updateLocation(_ location: [Double]) {
    // location was updated
}

示例2

正在更新PostManager以在init上接收LocationManager

class PostManager: ObservableObject {
    
    @Published var posts: [LocationPost] = []
    private var cancellable: AnyCancellable?    

    init(locationManager: LocationManager) {
        cancellable = locationManager.$location.sink() { location in
            // location is updated
        }
    }
}

示例3

如果您的View同时具有两个@StateObjects,则可以直接使用SwiftUI执行此操作。

struct MyView: View {
    @StateObject var locationManager = LocationManager()
    @StateObject var postManager = PostManager()
    
    var body: some View {
        VStack {
            
        }
        .onReceive(locationManager.$location) { location in
            postManager.updateLocation(location)
        }
    }
}
e4eetjau

e4eetjau2#

如果视图可以访问这两个ObservedObject,你可以在创建新帖子时从视图中传递位置:

在邮件管理器中:

func createPost(location: [Double], text: String) {
        posts.append(LocationPost(coordinates: location, text: text)) 
    }

在视图中

@StateObject var locationmanager = LocationManager()
@StateObject var postmanager = PostManager()

...

   postmanager.create(locationmanager.location, text: "my Message")

相关问题