将数据从 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)
}
...
如何将传入数据从 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)
}
...