Reputation: 15
In my project I have a Core Data entity called "Course" which contains the following attributes:-
name (String)
tee (String)
hole1no (Int16)
hole1index (Int16)
hole1par (Int16)
I use a fetch request and select the record required which is then used in variable calculations and text fields in my views.
I then have set up a "class" view to create ObsevableObject using @Published to enable certain data to be used across multiple views.
The issue I have is in my class setup I need to use a combination of data from the Core data and data entered in the views to calculate variables which are needed in multiple views.
Below is a copy of my code, in the ScoreManager class code I get the error message "Class ScoreManager has no initializers" which disappears if I remove any reference to the Course data so I presume that is what it is referring to in the error.
Any advice would be greatly appreciated, this is my first complex project so I may well be missing something in my knowledge. If possible could you update my code so I can see where the changes are to assist my learning.
Thanks in advance.
This is the code that fetches the data from Core Data
import SwiftUI
import CoreData
struct Score4PickCourse: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Course.entity(), sortDescriptors:[NSSortDescriptor(keyPath: \Course.name, ascending: false)]) var courses: FetchedResults<Course>
@State private var showingAddScreen = false
var body: some View {
List {
ForEach(courses, id: \.self) { course in NavigationLink(destination: Score4SelectPlayers(course: course)) {
VStack(alignment: .leading) {
Text(course.name ?? "Unknown Course")
Text(course.tee ?? "Unknown Tee")
}
}
}
}
.navigationBarTitle("Courses")
.navigationBarItems(trailing: Button(action: {
self.showingAddScreen.toggle()
}) {
Image(systemName: "plus")
}
)
.sheet(isPresented: $showingAddScreen) {
CourseAddNew().environment(\.managedObjectContext, self.moc)
}
}
}
This is the code where you enter basic information (player name, handicap etc.
import SwiftUI
import CoreData
struct Score4SelectPlayers: View {
@Environment(\.managedObjectContext) var moc
@Environment(\.presentationMode) var presentationMode
@ObservedObject var scoreManager = ScoreManager()
@State private var date = Date()
let course: Course
var body: some View {
Form {
Section {
Text("Course Selected - \(course.name ?? "No Course Selected")")
Text("Course Hole No - \(course.hole1no)")
Text("Tee Category Selected - \(course.tee ?? "No Tee Selected")")
DatePicker("Date of Round", selection: $date, displayedComponents: .date)
.foregroundColor(Color.blue)
.font(.system(size: 17, weight: .bold, design: .rounded))
TextField("Player 1 Name", text: $scoreManager.player1)
Picker("Player 1 Handicap", selection: $scoreManager.p1handicap) {
ForEach(Array(stride(from: 0, to: 55, by: 1)), id: \.self) { index in Text("\(index)")
}
} .frame(width: 300, height: 20, alignment: .center)
.foregroundColor(Color.blue)
.font(.system(size: 17, weight: .bold, design: .rounded))
}
}
NavigationLink(destination: Score4Hole1(scoreManager: scoreManager, course: course)) {
Text("Go To Hole 1")
}
}
}
struct Score4SelectPlayers_Previews: PreviewProvider {
static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
static var previews: some View {
let course = Course(context: moc)
course.name = "Great Barr"
course.tee = "White Tee"
course.hole1no = 1
course.hole1par = 5
course.hole1index = 10
return NavigationView {
CourseDetailView(course: course)
}
}
}
This is the class code where I need to be able to include data from Core Data in the variable calculations
import SwiftUI
import CoreData
class ScoreManager : ObservableObject {
let course: Course
@Published var player1 = ""
@Published var p1handicap = 0
var p1h1shots: Int16 {
let p1h1hand = Int16(p1handicap)
let index = Int16(course.hole1index)
let p1h1shot = p1h1hand - index
if p1h1shot < 0 {
return 0
}
if p1h1shot >= 0 && p1h1shot < 18 {
return 1
}
if p1h1shot >= 18 && p1h1shot < 36 {
return 2
}
if p1h1shot >= 36 && p1h1shot < 54 {
return 3
}
return 0
}
}
Upvotes: 1
Views: 255
Reputation: 29309
I can't test the code without a Minimal Reproducible Example but these changes could work. I don't know where you will be using it
1st:
CoreData objects are ObservableObjects
so in Score4SelectPlayers
change your course
to @ObservedObject var course: Course
2nd:
In your ScoreManager
change p1h1shots
to a func
func p1h1shots(hole1index: Int16) -> Int16 {
let p1h1hand = Int16(p1handicap)
let p1h1shot = p1h1hand - hole1index
if p1h1shot < 0 {
return 0
}
if p1h1shot >= 0 && p1h1shot < 18 {
return 1
}
if p1h1shot >= 18 && p1h1shot < 36 {
return 2
}
if p1h1shot >= 36 && p1h1shot < 54 {
return 3
}
return 0
}
and then you can use it in any View
with scoreManager.p1h1shots(hole1index: course.hole1index)
3rd: You can always just put it in your model
extension Course{
func p1h1shots(p1handicap: Int16) -> Int16 {
let index = Int16(hole1index)
let p1h1shot = p1handicap - index
if p1h1shot < 0 {
return 0
}
if p1h1shot >= 0 && p1h1shot < 18 {
return 1
}
if p1h1shot >= 18 && p1h1shot < 36 {
return 2
}
if p1h1shot >= 36 && p1h1shot < 54 {
return 3
}
return 0
}
}
and then use it course.p1h1shots(p1handicap: Int16)
in your View
Upvotes: 1