将数据从 Delegate Swift Class 传递到 SwiftUI 结构中的 EnvironmentObject

Passing Data from Delegate Swift Class to EnvironmentObject in SwiftUI Struct

如何将传入数据从 Swift class 中委托触发的方法传递到 EnvironmentObject?

我知道要使它起作用,我的 Swift class 需要来自 SwiftUI 结构(是 SwiftUI 的子结构父 SwiftUI 结构)。但是,我在 Apple Watch 应用程序的 ExtensionDelegate 中初始化了我的 Swift class。我希望在更新名称时看到 UI 文本元素发生变化。

以下代码在 Apple Watch 上运行:

class User: ObservableObject {
    
    @Published var id: UUID?
    @Published var name: String?
}
//SwiftUI struct
struct UI: View {

@EnvironmentObject var userEnv: User

var body: some View {
   Text(userEnv.name)
 }
}
// Swift class
class WatchConnectivityProvider: NSObject, WCSessionDelegate {

 static let shared = WatchConnectivityProvider()
 private let session: WCSession
    
    init(session: WCSession = .default) {
        self.session = session
        super.init()
    }
    
    func activateSession() {
        if WCSession.isSupported() {
            session.delegate = self
            session.activate()
        }
    }

    //This func gets triggered when data is sent from the iPhone
    func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
        
        let list = message["list"]
        
        let jsonDecoder = JSONDecoder()
        if let data = try? jsonDecoder.decode(User.self, from: list as! Data) {
            
        // !!! This is where I would like to update the EnvironmentObject userEnv !!!   
        // What is the best way to do this? Remember, this class has already been initialised within the ExtensionDelegate.
        }
    }
}
//ExtensionDelegate of Apple Watch app, initialising the WatchConnectivityProvider
class ExtensionDelegate: NSObject, WKExtensionDelegate {

    func applicationDidFinishLaunching() {
        // Perform any final initialization of your application.
        WatchConnectivityProvider.shared.activateSession()
    }
}

依赖注入

其中一个解决方案可能是在全球范围内存储对 @EnvironmentObject 的引用,例如。在一些依赖容器中。

enum Dependencies {
    struct Name: Equatable {
        let rawValue: String
        static let `default` = Name(rawValue: "__default__")
        static func == (lhs: Name, rhs: Name) -> Bool { lhs.rawValue == rhs.rawValue }
    }

    final class Container {
        private var dependencies: [(key: Dependencies.Name, value: Any)] = []

        static let `default` = Container()

        func register(_ dependency: Any, for key: Dependencies.Name = .default) {
            dependencies.append((key: key, value: dependency))
        }

        func resolve<T>(_ key: Dependencies.Name = .default) -> T {
            return (dependencies
                .filter { (dependencyTuple) -> Bool in
                    return dependencyTuple.key == key
                        && dependencyTuple.value is T
                }
                .first)?.value as! T
        }
    }
}

然后你像这样创建你的对象:

Dependencies.Container.default.register(User())

而且您可以从代码中的任何位置访问它:

let user: User = Dependencies.Container.default.resolve()
user.modify()

关于 Swift 的 Dependency Injection 的更详细解释可以在 here.

中找到

单例

或者,您可以使用标准 Singleton 模式使您的用户数据在全球范围内可用。可以找到更详细的解释.

最后的想法

Clean Architecture for SwiftUI 是一个很好的例子(至少在我看来),它说明了如何以 clean 的方式编写 iOS 应用程序。有点复杂,但是你可以挑一些部分。

这里是错误的 Jumbo 代码:

class ExtensionDelegate: ObservableObject, NSObject, WCSessionDelegate, WKExtensionDelegate {
var session: WCSession?
@Published var model = Model

func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) {
    print(#function)
    var replyValues = Dictionary<String, Any>()
    replyValues["status"] = "failed"
    
    // 2442 Bytes
    if let data = message["data"] as? Data {
        // push that work back to the main thread
        DispatchQueue.main.async {
            self.model = try? JSONDecoder().decode(Model.self, from: data)
        }
        if let vm = vm {
            replyValues["status"] = "ok"
            replyValues["id"] = vm.id.uuidString
        }
    }
    replyHandler(replyValues)
}
...