如何在现有的基于故事板的项目中设置@EnvironmentObject?

yaa*_*ali 6 uikit ios swift swiftui

我有一个使用StoryboardUIKit构建的 iOS 项目。现在我想使用SwiftUI开发新屏幕。我向现有Storyboard添加了一个托管视图控制器,并用它来显示我新创建的SwiftUI视图。

但我不知道如何创建一个可以在整个应用程序中的任何地方使用的@EnvironmenetObject 。我应该能够在任何基于 UIKit 的 ViewController 以及SwiftUI视图中访问/设置它。

这可能吗?如果是的话该怎么办呢?在纯SwiftUI应用程序中,我们设置环境对象如下,

@main
struct myApp: App {
    @StateObject var item = Item()

    var body: some Scene {
        WindowGroup {
            MainView()
                .environmentObject(item)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但就我而言,没有这样的函数,因为它是一个包含AppDelegateSceneDelegate的现有 iOS 项目。初始视图控制器在 Storyboard 中标记。如何设置它并在应用程序中的任何位置访问该对象?

Asw*_*ath 7

.environmentObject 修饰符将视图类型从 ItemDetailView 更改为其他类型。强制投射会导致错误。相反,请尝试将其包装到 AnyView 中。

class OrderObservable: ObservableObject {
    
    @Published var order: String = "Hello"
}

struct ItemDetailView: View {
    
    @EnvironmentObject var orderObservable: OrderObservable
    
    var body: some View {
        
        EmptyView()
            .onAppear(perform: {
                print(orderObservable.order)
            })
    }
}

class ItemDetailViewHostingController: UIHostingController<AnyView> {
    let appDelegate = UIApplication.shared.delegate as! AppDelegate

    required init?(coder: NSCoder) {
        super.init(coder: coder,rootView: AnyView(ItemDetailView().environmentObject(OrderObservable())))
    }
}
Run Code Online (Sandbox Code Playgroud)

这对我有用。这是你所需要的吗?

编辑:好的,所以我通过 ViewController 给出了设置属性。它不像使用属性包装器或视图修饰符那么容易,但它确实有效。我试了一下。请告诉我这是否满足您的要求。另外,我必须摆脱 HostingController 子类。

class ViewController: UIViewController {
    
    var orderObservable = OrderObservable()
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let myVC = (segue.destination as? MyViewController) else { return }
        myVC.orderObservable = orderObservable
    }
}

class MyViewController: UIViewController {
    
    var orderObservable: OrderObservable!
    var anycancellables = Set<AnyCancellable>()
    @IBAction @objc func buttonSegueToHostingVC() {
        let detailView = ItemDetailView().environmentObject(orderObservable)
        present(UIHostingController(rootView: detailView), animated: true)
        
        orderObservable.$order.sink { newVal in
            print(newVal)
        }
        .store(in: &anycancellables)
    }
}


class OrderObservable: ObservableObject {
    
    @Published var order: String = "Hello"
    
    init() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
            self.order = "World"
        }
    }
}

struct ItemDetailView: View {
    
    @EnvironmentObject var orderObservable: OrderObservable
    
    var body: some View {
        
        Text("\(orderObservable.order)")
    }
}
Run Code Online (Sandbox Code Playgroud)

基本上,我在 ViewController 类中创建可观察对象,将其传递给 MyViewController 类,最后使用 ItemDetailView 创建一个托管控制器,并设置它的environmentObject 并呈现它。