How do I pass a property from an ObservedObject
in a View
, to another class's initializer in the same View
? I get an error with my ObservedObject
:
Cannot use instance member 'project' within property initializer; property initializers run before 'self' is available
The reason I want to do this is I have a class which has properties that depend on a value from the ObservedObject
.
For example, I have an ObservedObject
called project
. I want to use the property, project.totalWordsWritten
, to change the session
class's property, session.totalWordCountWithSession
:
struct SessionView: View {
@Binding var isPresented: Bool
@ObservedObject var project: Project
// How to pass in project.totalWordsWritten from ObservedObject project to totalWordCount?
@StateObject var session:Session = Session(startDate: Date(), sessionWordCount: 300, totalWordCount: 4000)
var body: some View {
NavigationView {
VStack(alignment: .leading) {
Form {
Section {
Text("Count")
HStack {
Text("Session word count")
TextField("", value: $session.sessionWordCount, formatter: NumberFormatter())
.textFieldStyle(.roundedBorder)
}
HStack {
// Changing text field here should change the session count above
Text("Total word count")
TextField("", value: $session.totalWordCountWithSession, formatter: NumberFormatter())
.textFieldStyle(.roundedBorder)
}
}
}
}.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Save") {
// Save this session into the project
project.addSession(newSession: session)
isPresented = false
}
}
}
}
}
}
struct SessionView_Previews: PreviewProvider {
static var previews: some View {
SessionView(isPresented: .constant(true), project: Project(title: "TestProject", startWordCount: 0))
}
}
Below is the rest of the example:
HomeView.swift
import SwiftUI
struct HomeView: View {
@State private var showingSessionPopover:Bool = false
@StateObject var projectItem:Project = Project(title: "Test Project", startWordCount: 4000)
var body: some View {
NavigationView {
VStack(alignment: .leading) {
Text(projectItem.title).font(Font.custom("OpenSans-Regular", size: 18))
.fontWeight(.bold)
Text("Count today: \(projectItem.wordsWrittenToday)")
Text("Total: \(projectItem.totalWordsWritten)")
}
.toolbar {
ToolbarItem {
Button(action: {
showingSessionPopover = true
}, label: {
Image(systemName: "calendar").imageScale(.large)
}
)
}
}
}.popover(isPresented: $showingSessionPopover) {
SessionView(isPresented: $showingSessionPopover, project: projectItem)
}
}
}
Session.swift:
import Foundation
import SwiftUI
class Session: Identifiable, ObservableObject {
init(startDate:Date, sessionWordCount:Int, totalWordCount: Int) {
self.startDate = startDate
self.endDate = Calendar.current.date(byAdding: .minute, value: 30, to: startDate) ?? Date()
self.sessionWordCount = sessionWordCount
self.totalWordCount = totalWordCount
self.totalWordCountWithSession = self.totalWordCount + sessionWordCount
}
var id: UUID = UUID()
@Published var startDate:Date
@Published var endDate:Date
var totalWordCount: Int
var sessionWordCount:Int
@Published var totalWordCountWithSession:Int {
didSet {
sessionWordCount = totalWordCountWithSession - totalWordCount
}
}
}
Project.swift
import SwiftUI
class Project: Identifiable, ObservableObject {
var id: UUID = UUID()
@Published var title:String
var sessions:[Session] = []
@Published var wordsWrittenToday:Int = 0
@Published var totalWordsWritten:Int = 0
@Published var startWordCount:Int
init(title:String,startWordCount:Int) {
self.title = title
self.startWordCount = startWordCount
self.calculateDailyAndTotalWritten()
}
// Create a new session
func addSession(newSession:Session) {
sessions.append(newSession)
calculateDailyAndTotalWritten()
}
// Re-calculate how many
// today and in total for the project
func calculateDailyAndTotalWritten() {
wordsWrittenToday = 0
totalWordsWritten = startWordCount
for session in sessions {
if (Calendar.current.isDateInToday(session.startDate)) {
wordsWrittenToday += session.sessionWordCount
}
totalWordsWritten += session.sessionWordCount
}
}
}