【问题标题】:Using environmentObject in watchOS在 watchOS 中使用 environmentObject
【发布时间】:2019-06-12 06:15:00
【问题描述】:

我正在尝试在 watchOS6 应用中使用 environmentObject 将我的数据模型绑定到我的视图。

我在 Xcode 11 中创建了一个简单的独立 Watch 应用。

我创建了一个新的DataModel

import Combine
import Foundation
import SwiftUI

final class DataModel: BindableObject {

    let didChange = PassthroughSubject<DataModel,Never>()

    var aString: String = "" {
        didSet {
            didChange.send(self)
        }
    }

}

在我的ContentView 结构中,我使用@EnvironmentObject 绑定这个类 -

struct ContentView : View {

    @EnvironmentObject private var dataModel: DataModel

    var body: some View {
        Text($dataModel.aString.value)
    }
}

最后,我尝试将DataModel 的实例注入到HostingController 类中的环境中-

class HostingController : WKHostingController<ContentView> {
    override var body: ContentView {
        return ContentView().environmentObject(DataModel())
    }
}

但是,我得到一个错误:

Cannot convert return expression of type '_ModifiedContent<ContentView, _EnvironmentKeyWritingModifier<DataModel?>>' to return type 'ContentView'

错误是因为WKHostingController 是一个需要具体类型的泛型——在这种情况下为WKHostingController&lt;ContentView&gt;

类似的方法在 iOS 应用中与 UIHostingController 完美配合,因为 UIHostingController 不是泛型类。

还有其他方法可以将环境注入到 watchOS 视图中吗?

【问题讨论】:

标签: swift apple-watch watchos swiftui watchos-6


【解决方案1】:

您可以使用类型擦除,AnyView 在 SwiftUI 的情况下为 View

我会重构 WKHostingController 以返回 AnyView

这对我来说似乎编译得很好。

class HostingController : WKHostingController<AnyView> {
    override var body: AnyView {
        return AnyView(ContentView().environmentObject(DataModel()))
    }
}

【讨论】:

  • 谢谢。我试过AnyView,但我没有用过AnyView(ContentView())
  • 这对我不起作用,我收到以下错误:“'AnyView' 类型的属性'body' 无法覆盖'ContentView' 类型的属性”
  • 几个月后才回到这个问题上,新鲜的眼睛会有所帮助。我在通用协议声明中仍然有 ContentView,更改为 AnyView 并且可以工作。
  • 如何让子 ContentView 在最新的 WatchOS 应用程序模板中访问它?我在我的主要 ContentView 上工作,但是当我使用 NavigationLink 路由到视图时,我无法弄清楚 ContentView 如何访问相同的 @EnvironmentObject
  • 这是一个糟糕的答案,因为AnyView 性能很重。长话短说,将您的数据模型放在内容视图中。 Here's better solution
【解决方案2】:

对于像 Brett(在 cmets 中)这样的人来说,

"Property 'body' with type 'AnyView' cannot override a property with type 'ContentView'"

我得到了同样的错误,因为我没有替换返回值并包装了正在返回的 ContentView。

即。这是我第一次尝试的样子..注意 WKHostingController&lt;ContentView&gt; 那应该是 WKHostingController&lt;AnyView&gt;

class HostingController : WKHostingController<ContentView> {
    override var body: AnyView {
        return AnyView(ContentView().environmentObject(DataModel()))
    }
}

【讨论】:

  • 虽然我已经做了那一点,但我没有用 AnyView 替换 WKHostingController 中的 ContentView,这对我有用。感谢您的回复。
【解决方案3】:

添加到 Matteo 的精彩答案,

如果你想使用委托,那么这样使用:

class HostingController : WKHostingController<AnyView> {
    override var body: AnyView {
        var contentView = ContentView()
        contentView.environmentObject(DataModel())
        contentView.delegate = self
        let contentWrapperView = AnyView(contentView)
        return contentWrapperView
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-30
    • 2020-05-17
    • 2015-08-30
    • 2015-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多