I have a function that saves to viewContext
while in a detailView
. The function grabs the users location, so it isn’t instant. The function works properly if I stay on the detailView
for the item I selected, or go the to detialView
for a different item. If the user leaves the detailView
and goes back to the previous screen the function doesn’t work. I think this is due to there being no viewContext
. I’ve tried declaring the viewContext as a separate variable but I can’t get that to work.
This should be all of the code relevant to the question. I can post the locationManager
and CoreData
if needed.
import SwiftUI
@main
struct MyApp: App {
@StateObject private var locationManager = LocationManagerModel()
let persistanceController = PersistanceController.shared
var body: some Scene {
WindowGroup {
ContentView()
.environment(\.managedObjectContext, persistanceController.container.viewContext)
.environmentObject(locationManager)
.transition(AnyTransition.opacity.animation(.easeInOut(duration: 0.5)))
.accentColor(.green)
}
}
}
import SwiftUI
import CoreLocation
import CoreData
import Combine
struct ContentView: View {
@State private var shotClub = Club()
@State private var ballClub = Club()
@State private var showNewClub: Bool = false
@State var roundStarted = false
@EnvironmentObject var locationManager: LocationManagerModel
@AppStorage("NUMBER_KEY") var counter = 0
@AppStorage("NUMBER_KEY") var putts = 0
@AppStorage("BOOLEAN") var premium = false
var body: some View {
TabView{
ClubListView()
.tabItem {
Image(systemName: "list.bullet.rectangle.portrait")
}
.accentColor(Color.green)
}
}
}
import SwiftUI
struct ClubListView: View {
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(
entity: Club.entity(),
sortDescriptors:[],
animation: .default)
private var clubs:FetchedResults<Club>
@State private var shotClub = Club()
@State private var ballClub = Club()
@State private var showNewClub: Bool = false
@State private var showSettings: Bool = false
@EnvironmentObject var locationManager: LocationManagerModel
var body: some View {
let addNewShot = NewShotModel(locationManager: locationManager)
NavigationView{
ZStack {
List {
ForEach(clubs.sorted{$0.averageYardage > $1.averageYardage}) {club in
NavigationLink(destination: ClubDetailView(club: club, waiting: $locationManager.waiting, shotCoord: $locationManager.shotCoord, ballCoord: $locationManager.ballCoord, shotClub: $shotClub, ballClub: $ballClub, distanceYards: $locationManager.distanceYards, showError: $locationManager.showError)
.environmentObject(locationManager)
.onChange(of: locationManager.distanceChange, perform: {
value in
if locationManager.distanceYards != nil{
addNewShot.addNewShot(shotClub: shotClub, newShot: locationManager.distanceYards!, waiting: locationManager.waiting, ballClub: ballClub, viewContext: viewContext)
shotClub = ballClub
print(locationManager.distanceYards as Any)
}
}), label:{
ClubListRow(club: club, shotClub: $shotClub).environmentObject(locationManager)
} )
}
.onDelete(perform: deleteClub)
} //: List
} //: ZStack
.navigationTitle("Clubs")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(action: {
self.showNewClub = true
}) {
Image(systemName: "plus.circle.fill")
.foregroundColor(.accentColor)
} //: Button
} //: ToolbarItem
}
}
.environmentObject(locationManager)
.sheet(isPresented: $showNewClub) {
NewClubView(isShow: $showNewClub).accentColor(Color.green)
}
}
private func deleteClub(index: IndexSet) -> Void {
withAnimation {
index.map { clubs[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError.localizedDescription)")
}
}
}
}
import SwiftUI
import CoreLocation
import CoreData
struct ClubDetailView: View {
@ObservedObject var club: Club
@Environment(\.managedObjectContext) private var viewContext
@EnvironmentObject var locationManager: LocationManagerModel
@State var newShot: Int = 0
@Binding var waiting: Bool
@Binding var shotCoord: CLLocation?
@Binding var ballCoord: CLLocation?
@Binding var shotClub: Club
@Binding var ballClub: Club
@Binding var distanceYards: Int?
@Binding var showError: Bool
var body: some View{
ZStack {
VStack{
List {
if self.club.putter == false {
Section {
Text("Average distance: \(club.averageYardage) yards")
Text("\(club.strokesList.count) Strokes Counted")
Text("Distance Standard Deviation: \(lround(club.strokesStandardDeviation))y")
}
Section {
ForEach(club.strokesList, id: \.self) { stroke in
Text("\(stroke)y") // Display your stroke data here
}.onDelete(perform: deleteStroke)
}
} else {
Section {
Text("Average Putts per Hole: club.strokesList.count / holes played")
Text("\(club.strokesList.count) Strokes Counted")
}
}
}
Spacer()
if waiting == false && club.putter == false {
Button(action: {locationManager.currentLocation(mode: .shot)
shotClub = club
},label: {
Text("Swing Location")
.foregroundColor(.white)
.font(.system(.title, design: .rounded, weight: .bold))
.frame(maxWidth: .infinity)
})
.buttonStyle(.borderedProminent)
.alert("Shot Location has not been recorded. Please try again.", isPresented: $showError) {
Button("OK", role: .cancel) {}
}
}
if waiting && club == shotClub{
Button(action: {
waiting = false
}, label: {
Text("Now Tracking")
.foregroundColor(.white)
.font(.system(.title, design: .rounded, weight: .bold))
.frame(maxWidth: .infinity)
})
.buttonStyle(.borderedProminent)
.tint(.red)
}
if waiting && club != shotClub && club.putter == false{
Button(action: {locationManager.currentLocation(mode: .ball)
ballClub = club
}, label: {
Text("Ball Location")
.foregroundColor(.white)
.font(.system(.title, design: .rounded, weight: .bold))
.frame(maxWidth: .infinity)
})
.buttonStyle(.borderedProminent)
}
}
}
}
private func deleteStroke(at offsets: IndexSet) {
club.strokesList.remove(atOffsets: offsets)
do {
try viewContext.save()
} catch {
print("Error saving context: \(error)")
}
}
}
extension UINavigationController{
open override func viewWillLayoutSubviews() {
navigationBar.topItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
}
}
import SwiftUI
import CoreData
import CoreLocation
class NewShotModel: ObservableObject {
@Environment(\.managedObjectContext) private var viewContext
private let locationManager: LocationManagerModel
init(locationManager: LocationManagerModel) {
self.locationManager = locationManager
}
func addNewShot(shotClub: Club, newShot: Int, waiting: Bool, ballClub: Club, viewContext: NSManagedObjectContext) -> Void {
let shotClub = shotClub
let newShot = newShot
shotClub.strokesList.append(newShot)
do {
try viewContext.save()
print("shot saved")
locationManager.shotCoord = locationManager.ballCoord
} catch {
let nsError = error as NSError
print("Unresolved error \(nsError.localizedDescription)")
}
}
}