Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

Using `@ObservedObject` in a function

No real intruduction for this, so I'll get to the point: All this code is on GitHub: https://github.com/the-trumpeter/Timetaber-for-iWatch But first, sorry;

/*
I got roasted,
last time I posted;
for not defining my stuff.
This'll be different,
but's gonna be rough;
'cuz there's lots and lots
to get through:
*/

//this is 'Timetaber Watch App/Define (No expressions)/Courses_vDef.swift' on the GitHub:

struct Course {
    let name: String
    let icon: String
    let room: String
    let colour: String

    let listName: String
    let listIcon: String
    let joke: String

    init(name: String, icon: String, room: String? = nil, colour: String,
         listName: String? = nil, listIcon: String? = nil, joke: String? = nil)
    {

        self.name = name
        self.icon = icon
        self.room = room ?? "None"
        self.colour = colour

        self.listName = listName ?? name
        self.listIcon = listIcon ?? (icon+".circle.fill")

        self.joke = joke ?? ""
    }
}

//this is 'Timetaber Watch App/TimeManager_fDef.swift' on the GitHub:

func getCurrentClass(date: Date) -> Array<Course> {
//returns the course in session depending on the input date
//it is VERY long but
//all you really need to know is what it returns:
//basically: return [rightNow, nextUp]
}

/*
I thought that poetry
would be okay,
But poorly thought things through:
For I'll probably find
that people online
will treat my rhymes like spew.
*/

So into the question:

I have a bunch of views, all (intendedly) watching two variables inside of a class:

//Github: 'Timetaber Watch App/TimetaberApp.swift'
class GlobalData: ObservableObject {

    @Published var currentCourse: Course = getCurrentClass(date: .now)[0] // the current timetabled class in session.

    @Published var nextCourse: Course = getCurrentClass(date: .now)[1] // the next timetabled class in session
}

...and a bunch of views using them in different ways as follows: (Sorry, don't have the characters to define functions called in these)


import SwiftUI

//Github: 'Timetaber Watch App/Views/HomeView.swift'
struct HomeView: View {

    @StateObject var data = GlobalData()

    var body: some View {
        //HERE:
        let icon = data.currentCourse.icon
        let name = data.currentCourse.name
        let colour = data.currentCourse.colour
        let room = roomOrBlank(course: data.currentCourse)
        let next = data.nextCourse

        VStack {

            //CURRENT CLASS
            Image(systemName: icon)
                .foregroundColor(Color(colour))//add an SF symbol element
                .imageScale(.large)
                .font(.system(size: 25).weight(.semibold))

            Text(name)
                .font(.system(size:23).weight(.bold))
                .foregroundColor(Color(colour))
                .padding(.bottom, 0.1)

            //ROOM
            Text(room+"\n")
                .multilineTextAlignment(.center)
                .foregroundStyle(.gray)
                .font(.system(size: 15))

            if next.name != noSchool.name {
                Spacer()

                //NEXT CLASS
                Text(nextPrefix(course: next))
                    .font(.system(size: 15))

                Text(getNextString(course: next))
                    .font(.system(size: 15))
                    .multilineTextAlignment(.center)
            }
        }.padding()
    }
}

// Github: 'Timetaber Watch App/Views/ListView.swift'
struct listTemplate: View {

    @StateObject var data = GlobalData()

    var listedCourse: Course = failCourse(feedback: "lT.12")
    var courseTime: String = ""

    init(course: Course, courseTime: String) {
        self.courseTime = courseTime
        self.listedCourse = course
    }

    var body: some View {
        let localroom = if listedCourse.room == "None" {
            "" } else { listedCourse.room }
        let image = if listedCourse.listIcon == "custom1" {
            Image(.paintbrushPointedCircleFill)
        } else { Image(systemName: listedCourse.listIcon) }
        HStack{

            image
                .foregroundColor(Color(listedCourse.colour))
                .padding(.leading, 5)

            Text(listedCourse.name)
                .bold()

            Spacer()

            Text(courseTime)
            Text(localroom).bold().padding(.trailing, 5)

        }
        .padding(.bottom, 1)
        .background(data.currentCourse.name==listedCourse.name ? Color(listedCourse.colour).colorInvert(): nil) //HERE

    }
}

struct listedDay: View {
    let day: Dictionary<Int, Course>
    var body: some View {
        let dayKeys = Array(day.keys).sorted(by: <)
        List {
            ForEach((0...dayKeys.count-2), id: \.self) {
                let num = $0
                listTemplate(course: day[dayKeys[num]] ?? failCourse(feedback: "lD.53"), courseTime: time24toNormal(time24: dayKeys[num]))
            }
        }

    }
}

struct ListView: View {
    var body: some View {

        if storage.shared.termRunningGB && weekdayFunc(inDate: .now) != 1
            && weekdayFunc(inDate: .now) != 7 {
            ScrollView {
                listedDay(
                    day: getTimetableDay(
                        isWeekA:
                            getIfWeekIsA_FromDateAndGhost(
                                originDate: .now,
                                ghostWeek: storage.shared.ghostWeekGB
                            ),
                        weekDay: weekdayFunc(inDate: .now)
                    )
                )
            }

        } else if !storage.shared.termRunningGB {
            Text("There's no term running.\nThe day's classes will be displayed here.")
                .multilineTextAlignment(.center)
                .foregroundStyle(.gray)
                .font(.system(size: 13))

        } else {
            Text("No school today.\nThe day's classes will be displayed here.")
                .multilineTextAlignment(.center)
                .foregroundStyle(.gray)
                .font(.system(size: 13))
        }

    }
}

//There's one more view but I can't fit it for characters.
//On GitHub: 'Timetaber Watch App/Views/SettingsView.swift'

So... THE FUNCTION: This function is called when changes are made that will affect the correct output of getCurrentClass. It is intended to reload the views and the current/next variables to reflect those changes.\

//GHub: 'Timetaber Watch App/StorageManager.swift'
func reload() -> Void {

    @ObservedObject var globalData: GlobalData //this line is erroring, I don't know how to fix it. Is this even the best/proper way to do this?

    let courseData = getCurrentClass(date: .now)

    globalData.currentCourse = courseData[0]
    globalData.nextCourse = courseData[1]
//Variable '_globalData' used by function definition before being initialized
//that is the error appearing on those above two redefinitions.

    print("Setup done\n")
}

Thanks!

-Gill

var abc: Int = 5
// abc is 5. Yay! abc is 5!

var globalData: GlobalData... = ?
// What is globalData going to be? globalData is nothing, null, nada.

Since globalData is 'nothing' you cannot access the currentCourse or nextCourse attributes of that object, because it doesn't have those attributes in it yet.

You need to initialise the variable before you do something with it.

Using &#96;&#64;ObservedObject&#96; in a function
 
 
Q