LAST CHANCE: Save 50% on all my Swift books and bundles! >>

Day 28: the way to solve Challenge 3?

Forums > 100 Days of SwiftUI

Challenge 3 of BetterRest (day 28) requires us to make the idea of sleep time always show and update. I don't think anything we already know is enough to solve this so I had to google it and find out that I should use onChange and onAppear. However, I was wondering if this is the only way. Is there a solution that can solve this challenge by only using something we already learned before day 28?

3      

Hi @Shawn0919!

I don't think anything we already know is enough to solve this so I had to google it and find out that I should use onChange and onAppear.

Why is that? You can create computed property for that and use it. So initially you can have default values. And then once you change them your computed property will update the view for your sleep time.

    @State private var wakeUp = defaultWakeTime
    @State private var sleepAmount = 8.0
    @State private var coffeeAmount = 1

    static var defaultWakeTime: Date {
        var components = DateComponents()
        components.hour = 7
        components.minute = 0
        return Calendar.current.date(from: components) ?? Date.now
    }

    let numberOfCoffeCups = Array(1...20)

    // Using this property will update your view automatically once there is a change
    var calculateBedTime: String {
        do {
            let config = MLModelConfiguration()
            let model = try SleepCalculator(configuration: config)

            let components = Calendar.current.dateComponents([.hour, .minute], from: wakeUp)
            let hour = (components.hour ?? 0) * 60 * 60
            let minute = (components.minute ?? 0) * 60

            let prediction = try model.prediction(wake: Double(hour + minute), estimatedSleep: sleepAmount, coffee: Double(coffeeAmount))

            let sleepTime = wakeUp - prediction.actualSleep
            return "\(sleepTime.formatted(date: .omitted, time: .shortened))"

        } catch {
            return "Sorry there was a problem calculating your bedtime."
        }

    }

and in view you can use it something like this.

HStack {
    Spacer()
    Text("\(calculateBedTime)")
        .font(.system(size: 50))
        .fontWeight(.semibold)
        .padding([.top, .bottom], 30)
    Spacer()
}

3      

Thank you @ygeras for your response!

That's actually what i did in the first place, but I keep calculateBedTime as a function as what's in the tutorial, but by adding a return value, then calling it in that Text view, then weirdly, the code will compile and there are no errors, but the Text view will show nothing. Then just now I just tried yours way to make it a variable, then its still the same thing, no error but nothing show up. Here is my code piece:

    @State private var wakeUp = defaultWakeTime
    @State private var sleepAmount = 8.0
    @State private var coffeeAmount = 1

    static var defaultWakeTime: Date {
        var components = DateComponents()
        components.hour = 7
        components.minute = 0
        return Calendar.current.date(from: components) ?? Date.now
    }

    var calculateBedtime: String {
        do {
            let config = MLModelConfiguration()
            let model = try SleepCalculator(configuration: config)

            let components = Calendar.current.dateComponents([.hour, .minute], from: wakeUp)
            let hour = (components.hour ?? 0) * 60 * 60
            let minute = (components.minute ?? 0) * 60

            let prediction = try model.prediction(wake: Double(hour+minute), estimatedSleep: sleepAmount, coffee: Double(coffeeAmount))
            let sleepTime = wakeUp - prediction.actualSleep
//            alertTitle = "Your ideal bedtime is…"
            alertMessage = sleepTime.formatted(date: .omitted, time: .shortened)

        } catch {
//            alertTitle = "Error"
            alertMessage = "Error"
        }
//        showingAlert = true
        return alertMessage
    }

Then in the body:

VStack {
                    Text("Your idea bed time is ...")
                    HStack{
                        Spacer()
                        Text("\(calculateBedtime)")
                            .font(.largeTitle.bold())
                        Spacer()
                    }
                }
                .padding()

3      

But wait, in your calculateBedtime your return return alertMessage. You don't return String. So your computed property is setting alertMessage value. You need to return in similar way "\(sleepTime.formatted(date: .omitted, time: .shortened))" to make it work.

If you put that alert in your view that it will work:

Text("\(alertMessage)")

and then you will have to watch it change etc etc etc...

.onChange(of: wakeUp) { _ in
    calculateBedTime
}

and then you have to trigger calculateBedtime somewhere to make it return alertMessage. But again why to make those things complicated as you can use computed property

3      

Hacking with Swift is sponsored by Essential Developer.

SPONSORED Join a FREE crash course for mid/senior iOS devs who want to achieve an expert level of technical and practical skills – it’s the fast track to being a complete senior developer! Hurry up because it'll be available only until July 28th.

Click to save your free spot now

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.