无法在控制器中获取@EnvironmentObject。

6 浏览
0 Comments

无法在控制器中获取@EnvironmentObject。

我试图使用@EnvironmentObject来控制我的应用程序的某些方面。我遇到的问题是,我的一个控制器无法访问环境对象。我得到了致命错误“找不到Environment类型的@ObservableObject”。

我搜索了其他问题,我找到的每个解决方案都包括在相关视图中发送.environmentObject(myEnvironment)。问题是这不是一个视图,我似乎没有这个选项。

此外,在我的SceneDelegate中,我将environmentObject发送给第一个视图,所以那不是问题。

以下是我的代码。

首先,我创建了一个模型来声明所有的环境变量

Environment

struct Environment {

var showMenu: Bool

var searchText: String

var location : Location

init() {

self.showMenu = false

self.searchText = ""

self.location = Location()

}

}

接下来,我有一个控制器,它的目的是处理与环境相关的任何操作,现在它没有任何操作

EnvironmentController

import Foundation

class EnvironmentController : ObservableObject {

@Published var environment = Environment()

}

现在,在SceneDelegate中,我调用NextDeparturesView,然后调用MapView。

MapView

import SwiftUI

import MapKit

struct MapView : UIViewRepresentable {

@EnvironmentObject var environmentController: EnvironmentController

var locationController = LocationController()

func makeUIView(context: Context) -> MKMapView {

MKMapView(frame: .zero)

}

func updateUIView(_ uiView: MKMapView, context: Context) {

let coordinate = CLLocationCoordinate2D(

latitude: environmentController.environment.location.latitude,

longitude: environmentController.environment.location.longitude)

let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)

let region = MKCoordinateRegion(center: coordinate, span: span)

uiView.showsUserLocation = true

uiView.setRegion(region, animated: true)

}

}

你会注意到,在MapView中,我调用了LocationController,这就是致命错误发生的地方。

LocationController

import SwiftUI

import MapKit

import CoreLocation

final class LocationController: NSObject, CLLocationManagerDelegate, ObservableObject {

@EnvironmentObject var environmentController: EnvironmentController

@ObservedObject var userSettingsController = UserSettingsController()

var locationManager = CLLocationManager()

override init() {

super.init()

self.updateLocation()

}

func updateLocation() {

locationManager.delegate = self

locationManager.desiredAccuracy = kCLLocationAccuracyBest

if locationManager.responds(to: #selector(CLLocationManager.requestAlwaysAuthorization)){

locationManager.requestAlwaysAuthorization()

}

else {

locationManager.startUpdatingLocation()

}

}

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

print("Error updating location :%@", error)

}

func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

switch status {

case .notDetermined:

self.setDefaultLocation()

break

case .restricted:

self.setDefaultLocation()

break

case .denied:

self.setDefaultLocation()

break

default:

locationManager.startUpdatingLocation()

}

}

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

let currentLocation = manager.location?.coordinate

self.environmentController.environment.location.latitude = Double(currentLocation!.latitude)

self.environmentController.environment.location.longitude = Double(currentLocation!.longitude)

manager.stopUpdatingLocation()

}

func recenter() {

locationManager.startUpdatingLocation()

}

func setDefaultLocation() {

if self.$userSettingsController.userCity.wrappedValue == "" {

self.environmentController.environment.location.latitude = 0.0

self.environmentController.environment.location.longitude = 0.0

} else {

self.environmentController.environment.location.latitude = self.citiesDictionary[self.userSettingsController.userCity]!.latitude

self.environmentController.environment.location.longitude = self.citiesDictionary[self.userSettingsController.userCity]!.longitude

}

}

}

所以,这就是致命错误发生的地方。例如,我的应用程序通常首先调用`setDefaultLocation()`,并且应用程序在那里崩溃。你有什么想法我做错了什么,或者如何解决这个问题?

提前谢谢你的帮助。

编辑

在得到了@pawello2222的很多帮助后,我解决了我的问题,但是对整个应用程序的结构进行了一些更改。

我将接受他的答案作为正确答案,但是我将提供我所做的事情的列表,这样以后看到这个问题的人可能会朝正确的方向前进。

  1. 我错误地认为都可以访问<@EnvironmentObject>。只有才能。
  2. 在我的结构中,我现在有一个而不是<@Published var location: Location>,因此在整个应用程序中使用相同的实例。在我的中,我现在有一个<@Published var location: Location>,所以每个视图都可以访问相同的位置。
  3. 类型的结构中,我创建<@EnvironmentObject var environmentController: EnvironmentController>并使用与之关联的。在其他类类型中,我简单地有一个方法接收,这通过发送,例如当我调用时,我这样做:,确保在整个应用程序中使用的是相同的控制器和相同的正在被更改。重要的是,在类如中使用<@ObservedObject var locationController: LocationController>,否则不会检测到更改。

希望对你有所帮助。

0
0 Comments

无法在控制器中获取@EnvironmentObject。

问题的原因是不能在Controller/ViewModel(实际上在View之外的任何地方)中使用。如果要在控制器中观察环境的变化,可以这样做:

class Environment: ObservableObject {

@Published var showMenu: Bool = false

@Published var searchText: String = ""

@Published var location: Location = Location()

}

class Controller: ObservableObject {

@Published var showMenu: Bool = false

private var cancellables = Set()

init(environment: Environment) {

environment.$showMenu

.receive(on: DispatchQueue.main)

.assign(to: \.showMenu, on: self)

.store(in: &cancellables)

}

}

你也可以使用其他形式的依赖注入来注入Environment(甚至使用单例)。

通常有不同的方法来显示View中的Environment变量(例如showMenu)并刷新它:

1. 将Environment作为环境对象注入到View中(而不是ViewModel),作为一个@EnvironmentObject - 用于在View中访问Environment的情况。

2. ViewModel订阅Environment,并将自己的变量发布给View。在这种情况下,不需要在View中使用@EnvironmentObject。

3. 将Environment作为环境对象注入到View中,并传递给ViewModel。

如果在调用LocationController的视图(MapView)中没有该对象,则无法访问环境对象。例如,我的入口点视图具有该对象,我是否可以简单地调用MapView()?还是必须调用MapView().environmentObject(envObject)?

谢谢。我正在尝试执行第3个选项。我编辑了我的问题以显示发生了什么。希望你能帮助我。

UIViewRepresentable与View不同。尝试在init中将Environment传递给你的MapView。类似这样:MapView(environmentController: environmentController)。

我已经尝试了这个,但是我仍然无法将参数分配给environmentController或locationController。我必须删除符号吗?我更新了代码,你可以看到我的意思。

不能在View之外使用属性包装器。从environmentController的声明中移除,问题应该就解决了。

让我们在聊天中继续讨论

0