在SwiftUI Struct中将数据从委托Swift类传递给EnvironmentObject

时间:2020-06-01 16:58:49

标签: swift swiftui watchos

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

我知道要执行此操作,需要从SwiftUI结构(作为父SwiftUI结构的子代)调用/初始化我的Swift类。但是,我在Apple Watch应用程序的ExtensionDelegate中初始化了我的Swift类。我希望看到更新名称时UI Text元素发生变化。

以下代码在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()
    }
}

1 个答案:

答案 0 :(得分:0)

依赖注入

一种解决方案是将对@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()

有关Dependency Injection的Swift的更详细说明,请参见here

单人

或者,您可以使用标准的Singleton模式来使您的用户数据全局可用。可以找到更详细的解释here

最终想法

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