具有核心位置的 SwiftUI 作为 ObservableObject 崩溃
SwiftUI with Core Location as ObservableObject crashes
我正在尝试使用 Core Location 获取 CLRegionState 以更新 SwiftUI 应用程序中的元素。我正在使用 XCode 11 beta 6 并在我的设备上安装了 iOS 13 beta 7。
我看到有两个问题:
应用程序崩溃,错误 Thread 1: EXC_BAD_ACCESS
出现在行 147
(...ScrollView {... )
从未调用或不更新 CLRegionState。
我基于 Paul Hudson 关于 SwiftUI Beacon Detector 的教程(我也无法完成),并将其修改为使用 CLRegionState 而不是 beacon proximity 。
代码如下:
import SwiftUI
import CoreLocation
import Combine
class MYLocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
var willChange = PassthroughSubject<Void, Never>()
var lastRegionState = CLRegionState.unknown
override init() {
super.init()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
func update(state: CLRegionState) {
lastRegionState = state
willChange.send(())
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
print("Your location is \(location)")
update(state: .unknown)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func startScanning() {
// temporary coordinates
var workCoordinates: CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: 43.486525,
longitude: -11.912542)
}
var homeCoordinates = CLLocationCoordinate2D(
latitude: 43.499541,
longitude: -11.875079)
let workRegion: CLCircularRegion = CLCircularRegion(center: workCoordinates, radius: 100, identifier: "Work")
let homeRegion: CLCircularRegion = CLCircularRegion(center: homeCoordinates, radius: 100, identifier: "Home")
locationManager!.startMonitoring(for: workRegion)
locationManager!.startMonitoring(for: homeRegion)
locationManager!.requestState(for: workRegion)
locationManager!.requestState(for: homeRegion)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
switch state {
case .inside:
switch region.identifier {
case "Work":
print("You are at work")
case "Home":
print("You are at home")
default:
print("unknown")
}
default:
break
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
switch region.identifier {
case "Work":
print("Work**********")
//self.taskTypeSegCtrl.selectedSegmentIndex = 0
case "Home":
print("Home*********8")
//self.taskTypeSegCtrl.selectedSegmentIndex = 1
default:
break
}
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
startScanning()
break
case .authorizedAlways:
startScanning()
break
case .denied:
// show an alert instructing them howto turn on permissions
break
case .notDetermined:
print("Location authorization is not determined.")
locationManager!.requestAlwaysAuthorization()
break
case .restricted:
break
@unknown default:
fatalError()
}
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(
keyPath: \Task.name, ascending: true)])
var tasks: FetchedResults<Task>
var locationManager = CLLocationManager()
@ObservedObject var location: MYLocationManager = MYLocationManager()
@State private var taskName = ""
@State private var taskType = 0
@State private var selectedTask = ""
@State private var numberOfTaps = 0
@State private var regionState = CLRegionState.unknown
var body: some View {
ScrollView {
VStack {
TextField("Enter a task name", text: $taskName)
.textFieldStyle(RoundedBorderTextFieldStyle())
Picker(selection: $taskType, label: Text("Task type")) {
Text("Work").tag(1)
Text("Home").tag(2)
}.pickerStyle(SegmentedPickerStyle())
Text(selectedTask)
Button(action: {
let task = Task(context: self.managedObjectContext)
task.name = self.taskName
task.type = Int16(self.taskType)
do {
try self.managedObjectContext.save()
} catch {
// handle the Core Data error
}
self.taskName = ""
}) {
Text("Save Task")
}.padding()
Button(action: {
if self.numberOfTaps < self.tasks.count {
let task = self.tasks[self.numberOfTaps].name
self.selectedTask = task ?? "No task..."
self.numberOfTaps = self.numberOfTaps + 1
} else {
self.selectedTask = "No more tasks! Have a wonderful day."
}
}) {
Text("Next Task")
}
List {
ForEach(tasks, id: \.self) { task in
VStack(alignment: .leading, spacing: 6) {
Text(task.name ?? "Unknown")
.font(.headline)
Text("Task type \(task.type)")
.font(.caption)
}
}.onDelete(perform: removeTask)
}
} .frame(width: 300, height: 400, alignment: .top)
.padding()
.border(Color.black)
if regionState == .inside {
Text("inside")
} else if regionState == .outside {
Text("outside")
} else {
Text("unknown")
}
Spacer()
}
}
func removeTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
managedObjectContext.delete(task)
do {
try managedObjectContext.save()
} catch {
// handle the Core Data error
}
}
}
func showTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
selectedTask = task.name ?? "No task..."
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
执行 Fabian 所做的更改后,控制台日志的内容如下:
Granted: true
2019-08-22 14:30:07.051062-0600 AppName[4452:2089841] locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)
2019-08-22 14:30:07.052803-0600 New1Thing[4452:2089841] startScanning
2019-08-22 14:30:07.054319-0600 New1Thing[4452:2089841] Current location: <+**.49945068,-***.87504490> +/- 65.00m (speed -1.00 mps / course -1.00) @ 8/22/19, 2:30:07 PM **** Daylight Time
这是一个完整的工作示例。我解决了几个问题。
ObservableObject
现在可以使用 objectWillChange
而不是 willChange
。
- 它现在应该在每次状态变化时更新。
之前更新的部分没有完成(我的意见)
import SwiftUI
import CoreLocation
import Combine
import CoreData
import os
class MYLocationManager: NSObject, ObservableObject {
var locationManager: CLLocationManager?
var objectWillChange = PassthroughSubject<Void, Never>()
@Published var lastRegionState = CLRegionState.unknown {
willSet {
objectWillChange.send()
}
}
@Published var currentRegion: Region = .nowhereKnown {
willSet {
objectWillChange.send()
}
}
override init() {
super.init()
locationManager = CLLocationManager()
locationManager!.delegate = self
locationManager!.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
fatalError("error: \(error.localizedDescription)")
}
enum Region: String {
case work = "Work"
case home = "Home"
case nowhereKnown = "Nowhere Known"
}
func startScanning() {
os_log("startScanning")
// temporary coordinates
var workCoordinates: CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: 43.486525,
longitude: -11.912542)
}
var homeCoordinates = CLLocationCoordinate2D(
latitude: 43.499541,
longitude: -11.875079)
if let currentLocation = locationManager?.location {
os_log("Current location: %@", currentLocation.description)
homeCoordinates = currentLocation.coordinate
} else {
os_log("Current location: failed")
}
let workRegion: CLCircularRegion = CLCircularRegion(center: workCoordinates, radius: 100, identifier: Region.work.rawValue)
let homeRegion: CLCircularRegion = CLCircularRegion(center: homeCoordinates, radius: 100, identifier: Region.home.rawValue)
locationManager!.startMonitoring(for: workRegion)
locationManager!.startMonitoring(for: homeRegion)
locationManager!.requestState(for: workRegion)
locationManager!.requestState(for: homeRegion)
}
}
// MARK: Authorization
extension MYLocationManager {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
os_log("locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)")
checkLocationAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
os_log("locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])")
guard let location = locations.last else { return }
print("Your location is \(location)")
update(state: .unknown)
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
startScanning()
break
case .authorizedAlways:
startScanning()
break
case .denied:
// show an alert instructing them howto turn on permissions
break
case .notDetermined:
print("Location authorization is not determined.")
locationManager!.requestAlwaysAuthorization()
break
case .restricted:
break
@unknown default:
fatalError()
}
}
}
// MARK: UI Updates
extension MYLocationManager: CLLocationManagerDelegate {
func updateCurrentRegion(region: CLRegion) {
guard let region = Region(rawValue: region.identifier) else {
currentRegion = .nowhereKnown
return
}
currentRegion = region
}
func update(state: CLRegionState) {
lastRegionState = state
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
self.lastRegionState = state
updateCurrentRegion(region: region)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
updateCurrentRegion(region: region)
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
updateCurrentRegion(region: region)
}
}
struct CoreLocationView: View {
private static func makeContainer() -> NSPersistentContainer {
let store = NSPersistentContainer(name: "CoreLocationView")
store.loadPersistentStores { (desc, err) in
if let err = err {
fatalError("core data error: \(err)")
}
}
return store
}
let container: NSPersistentContainer
init() {
self.container = CoreLocationView.makeContainer()
}
var body: some View {
CoreLocationView_NeedsEnv().environment(\.managedObjectContext, container.viewContext)
}
}
struct CoreLocationView_NeedsEnv: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(
keyPath: \Task.name, ascending: true)])
var tasks: FetchedResults<Task>
var locationManager = CLLocationManager()
@ObservedObject var location: MYLocationManager = MYLocationManager()
@State private var taskName = ""
@State private var taskType = 0
@State private var selectedTask = ""
@State private var numberOfTaps = 0
//@State private var regionState = CLRegionState.unknown
var body: some View {
ScrollView {
VStack {
TextField("Enter a task name", text: $taskName)
.textFieldStyle(RoundedBorderTextFieldStyle())
Picker(selection: $taskType, label: Text("Task type")) {
Text("Work").tag(1)
Text("Home").tag(2)
}.pickerStyle(SegmentedPickerStyle())
Text(selectedTask)
Button(action: {
let task = Task(context: self.managedObjectContext)
task.name = self.taskName
task.type = Int16(self.taskType)
do {
try self.managedObjectContext.save()
} catch {
// handle the Core Data error
}
self.taskName = ""
}) {
Text("Save Task")
}.padding()
Button(action: {
if self.numberOfTaps < self.tasks.count {
let task = self.tasks[self.numberOfTaps].name
self.selectedTask = task ?? "No task..."
self.numberOfTaps = self.numberOfTaps + 1
} else {
self.selectedTask = "No more tasks! Have a wonderful day."
}
}) {
Text("Next Task")
}
List {
ForEach(tasks, id: \.self) {
task in
VStack(alignment: .leading, spacing: 6) {
Text(task.name ?? "Unknown")
.font(.headline)
Text("Task type \(task.type)")
.font(.caption)
}
}.onDelete(perform: removeTask)
}
} .frame(width: 300, height: 400, alignment: .top)
.padding()
.border(Color.black)
if location.lastRegionState == .inside {
Text("inside")
} else if location.lastRegionState == .outside {
Text("outside")
} else {
Text("unknown")
}
Text("Where am I: \(location.currentRegion.rawValue)")
Spacer()
}
}
func removeTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
managedObjectContext.delete(task)
do {
try managedObjectContext.save()
} catch {
// handle the Core Data error
}
}
}
func showTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
selectedTask = task.name ?? "No task..."
}
}
}
首先要感谢 Fabian 和 graycampbell 的帮助。
其次,据我所知,@ObservableObject 在 iOS 13 beta 8 中使用 XCode 11 beta 6 仍然不起作用。
以下是对我有用的方法:
1.我改了
@ObservedObject var location: MYLocationManager = MYLocationManager()
至:
@EnvironmentObject var location: MYLocationManager
2。在我添加的 SceneDelegate 中:
let myLocationManager = MYLocationManager()
和:
window.rootViewController = UIHostingController(rootView: CoreLocationView_NeedsEnv()
.environmentObject(myLocationManager)
不再崩溃!!
P.S。我正在使用 Fabian 的更新代码。再次感谢!
我正在尝试使用 Core Location 获取 CLRegionState 以更新 SwiftUI 应用程序中的元素。我正在使用 XCode 11 beta 6 并在我的设备上安装了 iOS 13 beta 7。
我看到有两个问题:
应用程序崩溃,错误
Thread 1: EXC_BAD_ACCESS
出现在行147
(...ScrollView {... )从未调用或不更新 CLRegionState。
我基于 Paul Hudson 关于 SwiftUI Beacon Detector 的教程(我也无法完成),并将其修改为使用 CLRegionState 而不是 beacon proximity 。
代码如下:
import SwiftUI
import CoreLocation
import Combine
class MYLocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
var locationManager: CLLocationManager?
var willChange = PassthroughSubject<Void, Never>()
var lastRegionState = CLRegionState.unknown
override init() {
super.init()
locationManager = CLLocationManager()
locationManager?.delegate = self
locationManager?.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
func update(state: CLRegionState) {
lastRegionState = state
willChange.send(())
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
print("Your location is \(location)")
update(state: .unknown)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func startScanning() {
// temporary coordinates
var workCoordinates: CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: 43.486525,
longitude: -11.912542)
}
var homeCoordinates = CLLocationCoordinate2D(
latitude: 43.499541,
longitude: -11.875079)
let workRegion: CLCircularRegion = CLCircularRegion(center: workCoordinates, radius: 100, identifier: "Work")
let homeRegion: CLCircularRegion = CLCircularRegion(center: homeCoordinates, radius: 100, identifier: "Home")
locationManager!.startMonitoring(for: workRegion)
locationManager!.startMonitoring(for: homeRegion)
locationManager!.requestState(for: workRegion)
locationManager!.requestState(for: homeRegion)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
switch state {
case .inside:
switch region.identifier {
case "Work":
print("You are at work")
case "Home":
print("You are at home")
default:
print("unknown")
}
default:
break
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
switch region.identifier {
case "Work":
print("Work**********")
//self.taskTypeSegCtrl.selectedSegmentIndex = 0
case "Home":
print("Home*********8")
//self.taskTypeSegCtrl.selectedSegmentIndex = 1
default:
break
}
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
startScanning()
break
case .authorizedAlways:
startScanning()
break
case .denied:
// show an alert instructing them howto turn on permissions
break
case .notDetermined:
print("Location authorization is not determined.")
locationManager!.requestAlwaysAuthorization()
break
case .restricted:
break
@unknown default:
fatalError()
}
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(
keyPath: \Task.name, ascending: true)])
var tasks: FetchedResults<Task>
var locationManager = CLLocationManager()
@ObservedObject var location: MYLocationManager = MYLocationManager()
@State private var taskName = ""
@State private var taskType = 0
@State private var selectedTask = ""
@State private var numberOfTaps = 0
@State private var regionState = CLRegionState.unknown
var body: some View {
ScrollView {
VStack {
TextField("Enter a task name", text: $taskName)
.textFieldStyle(RoundedBorderTextFieldStyle())
Picker(selection: $taskType, label: Text("Task type")) {
Text("Work").tag(1)
Text("Home").tag(2)
}.pickerStyle(SegmentedPickerStyle())
Text(selectedTask)
Button(action: {
let task = Task(context: self.managedObjectContext)
task.name = self.taskName
task.type = Int16(self.taskType)
do {
try self.managedObjectContext.save()
} catch {
// handle the Core Data error
}
self.taskName = ""
}) {
Text("Save Task")
}.padding()
Button(action: {
if self.numberOfTaps < self.tasks.count {
let task = self.tasks[self.numberOfTaps].name
self.selectedTask = task ?? "No task..."
self.numberOfTaps = self.numberOfTaps + 1
} else {
self.selectedTask = "No more tasks! Have a wonderful day."
}
}) {
Text("Next Task")
}
List {
ForEach(tasks, id: \.self) { task in
VStack(alignment: .leading, spacing: 6) {
Text(task.name ?? "Unknown")
.font(.headline)
Text("Task type \(task.type)")
.font(.caption)
}
}.onDelete(perform: removeTask)
}
} .frame(width: 300, height: 400, alignment: .top)
.padding()
.border(Color.black)
if regionState == .inside {
Text("inside")
} else if regionState == .outside {
Text("outside")
} else {
Text("unknown")
}
Spacer()
}
}
func removeTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
managedObjectContext.delete(task)
do {
try managedObjectContext.save()
} catch {
// handle the Core Data error
}
}
}
func showTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
selectedTask = task.name ?? "No task..."
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
执行 Fabian 所做的更改后,控制台日志的内容如下:
Granted: true
2019-08-22 14:30:07.051062-0600 AppName[4452:2089841] locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)
2019-08-22 14:30:07.052803-0600 New1Thing[4452:2089841] startScanning
2019-08-22 14:30:07.054319-0600 New1Thing[4452:2089841] Current location: <+**.49945068,-***.87504490> +/- 65.00m (speed -1.00 mps / course -1.00) @ 8/22/19, 2:30:07 PM **** Daylight Time
这是一个完整的工作示例。我解决了几个问题。
ObservableObject
现在可以使用objectWillChange
而不是willChange
。- 它现在应该在每次状态变化时更新。
之前更新的部分没有完成(我的意见)
import SwiftUI
import CoreLocation
import Combine
import CoreData
import os
class MYLocationManager: NSObject, ObservableObject {
var locationManager: CLLocationManager?
var objectWillChange = PassthroughSubject<Void, Never>()
@Published var lastRegionState = CLRegionState.unknown {
willSet {
objectWillChange.send()
}
}
@Published var currentRegion: Region = .nowhereKnown {
willSet {
objectWillChange.send()
}
}
override init() {
super.init()
locationManager = CLLocationManager()
locationManager!.delegate = self
locationManager!.requestWhenInUseAuthorization()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
fatalError("error: \(error.localizedDescription)")
}
enum Region: String {
case work = "Work"
case home = "Home"
case nowhereKnown = "Nowhere Known"
}
func startScanning() {
os_log("startScanning")
// temporary coordinates
var workCoordinates: CLLocationCoordinate2D {
return CLLocationCoordinate2D(
latitude: 43.486525,
longitude: -11.912542)
}
var homeCoordinates = CLLocationCoordinate2D(
latitude: 43.499541,
longitude: -11.875079)
if let currentLocation = locationManager?.location {
os_log("Current location: %@", currentLocation.description)
homeCoordinates = currentLocation.coordinate
} else {
os_log("Current location: failed")
}
let workRegion: CLCircularRegion = CLCircularRegion(center: workCoordinates, radius: 100, identifier: Region.work.rawValue)
let homeRegion: CLCircularRegion = CLCircularRegion(center: homeCoordinates, radius: 100, identifier: Region.home.rawValue)
locationManager!.startMonitoring(for: workRegion)
locationManager!.startMonitoring(for: homeRegion)
locationManager!.requestState(for: workRegion)
locationManager!.requestState(for: homeRegion)
}
}
// MARK: Authorization
extension MYLocationManager {
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
os_log("locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus)")
checkLocationAuthorization()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
os_log("locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])")
guard let location = locations.last else { return }
print("Your location is \(location)")
update(state: .unknown)
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
startScanning()
break
case .authorizedAlways:
startScanning()
break
case .denied:
// show an alert instructing them howto turn on permissions
break
case .notDetermined:
print("Location authorization is not determined.")
locationManager!.requestAlwaysAuthorization()
break
case .restricted:
break
@unknown default:
fatalError()
}
}
}
// MARK: UI Updates
extension MYLocationManager: CLLocationManagerDelegate {
func updateCurrentRegion(region: CLRegion) {
guard let region = Region(rawValue: region.identifier) else {
currentRegion = .nowhereKnown
return
}
currentRegion = region
}
func update(state: CLRegionState) {
lastRegionState = state
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
self.lastRegionState = state
updateCurrentRegion(region: region)
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
updateCurrentRegion(region: region)
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
updateCurrentRegion(region: region)
}
}
struct CoreLocationView: View {
private static func makeContainer() -> NSPersistentContainer {
let store = NSPersistentContainer(name: "CoreLocationView")
store.loadPersistentStores { (desc, err) in
if let err = err {
fatalError("core data error: \(err)")
}
}
return store
}
let container: NSPersistentContainer
init() {
self.container = CoreLocationView.makeContainer()
}
var body: some View {
CoreLocationView_NeedsEnv().environment(\.managedObjectContext, container.viewContext)
}
}
struct CoreLocationView_NeedsEnv: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(
keyPath: \Task.name, ascending: true)])
var tasks: FetchedResults<Task>
var locationManager = CLLocationManager()
@ObservedObject var location: MYLocationManager = MYLocationManager()
@State private var taskName = ""
@State private var taskType = 0
@State private var selectedTask = ""
@State private var numberOfTaps = 0
//@State private var regionState = CLRegionState.unknown
var body: some View {
ScrollView {
VStack {
TextField("Enter a task name", text: $taskName)
.textFieldStyle(RoundedBorderTextFieldStyle())
Picker(selection: $taskType, label: Text("Task type")) {
Text("Work").tag(1)
Text("Home").tag(2)
}.pickerStyle(SegmentedPickerStyle())
Text(selectedTask)
Button(action: {
let task = Task(context: self.managedObjectContext)
task.name = self.taskName
task.type = Int16(self.taskType)
do {
try self.managedObjectContext.save()
} catch {
// handle the Core Data error
}
self.taskName = ""
}) {
Text("Save Task")
}.padding()
Button(action: {
if self.numberOfTaps < self.tasks.count {
let task = self.tasks[self.numberOfTaps].name
self.selectedTask = task ?? "No task..."
self.numberOfTaps = self.numberOfTaps + 1
} else {
self.selectedTask = "No more tasks! Have a wonderful day."
}
}) {
Text("Next Task")
}
List {
ForEach(tasks, id: \.self) {
task in
VStack(alignment: .leading, spacing: 6) {
Text(task.name ?? "Unknown")
.font(.headline)
Text("Task type \(task.type)")
.font(.caption)
}
}.onDelete(perform: removeTask)
}
} .frame(width: 300, height: 400, alignment: .top)
.padding()
.border(Color.black)
if location.lastRegionState == .inside {
Text("inside")
} else if location.lastRegionState == .outside {
Text("outside")
} else {
Text("unknown")
}
Text("Where am I: \(location.currentRegion.rawValue)")
Spacer()
}
}
func removeTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
managedObjectContext.delete(task)
do {
try managedObjectContext.save()
} catch {
// handle the Core Data error
}
}
}
func showTask(at offsets: IndexSet) {
for index in offsets {
let task = tasks[index]
selectedTask = task.name ?? "No task..."
}
}
}
首先要感谢 Fabian 和 graycampbell 的帮助。
其次,据我所知,@ObservableObject 在 iOS 13 beta 8 中使用 XCode 11 beta 6 仍然不起作用。
以下是对我有用的方法: 1.我改了
@ObservedObject var location: MYLocationManager = MYLocationManager()
至:
@EnvironmentObject var location: MYLocationManager
2。在我添加的 SceneDelegate 中:
let myLocationManager = MYLocationManager()
和:
window.rootViewController = UIHostingController(rootView: CoreLocationView_NeedsEnv()
.environmentObject(myLocationManager)
不再崩溃!!
P.S。我正在使用 Fabian 的更新代码。再次感谢!