简体   繁体   中英

SwiftUI: ObservableObject with a computed property

I have a simple View with a custom month selector. Each time you click chevron left or right,

Inside DateView I had two private vars: startDateOfMonth2: Date and endDateOfMonth2: Date . But they were only available inside DateView.

QUESTION

How to make those two variables available in other views?

I have tried to add them as @Published vars, but I am getting an error:

Property wrapper cannot be applied to a computed property

I have found just a few similar questions, but I cannot manage to use answers from them with my code.

import SwiftUI

class SelectedDate: ObservableObject {
    @Published var selectedMonth: Date = Date()
    
    @Published var startDateOfMonth2: Date {
        let components = Calendar.current.dateComponents([.year, .month], from: selectedMonth)
        let startOfMonth = Calendar.current.date(from: components)!
        return startOfMonth
    }

    @Published var endDateOfMonth2: Date {
        var components = Calendar.current.dateComponents([.year, .month], from: selectedMonth)
        components.month = (components.month ?? 0) + 1
        let endOfMonth = Calendar.current.date(from: components)!
        return endOfMonth
    }
}

struct DateView: View {
    @EnvironmentObject var selectedDate: SelectedDate
    
    static let dateFormat: DateFormatter = {
        let formatter = DateFormatter()
        formatter.setLocalizedDateFormatFromTemplate("yyyy MMMM")
        return formatter
    }()
    
    var body: some View {
        
        HStack {
            
            Image(systemName: "chevron.left")
                .frame(width: 50, height: 50)
                .contentShape(Rectangle())
                .onTapGesture {
                    self.changeMonthBy(-1)
            }
            
            Spacer()

            Text("\(selectedDate.selectedMonth, formatter: Self.dateFormat)")
            
            Spacer()
            
            Image(systemName: "chevron.right")
                .frame(width: 50, height: 50)
                .contentShape(Rectangle())
                .onTapGesture {
                    self.changeMonthBy(1)
            }
            
        }
        .padding(EdgeInsets(top: 5, leading: 5, bottom: 5, trailing: 5))
        .background(Color.yellow)
    }
    
    func changeMonthBy(_ months: Int) {
        if let selectedMonth = Calendar.current.date(byAdding: .month, value: months, to: selectedDate.selectedMonth) {
            self.selectedDate.selectedMonth = selectedMonth
        }
    }
}

No need to declare your computed values as Published, as they are depending on a Published value. When the published value changed, they get recalculated.

class SelectedDate: ObservableObject {
    @Published var selectedMonth: Date = Date()
    
    var startDateOfMonth2: Date {
        let components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
        let startOfMonth = Calendar.current.date(from: components)!
        
        print(startOfMonth)
        return startOfMonth
    }

    var endDateOfMonth2: Date {
        var components = Calendar.current.dateComponents([.year, .month], from: self.selectedMonth)
        components.month = (components.month ?? 0) + 1
        let endOfMonth = Calendar.current.date(from: components)!

        print(endOfMonth)
        return endOfMonth
    }
}

When you print endDateOfMonth2 on click, you will see that it is changing.

computed property is function substantially。 it can't stored value,it just computed value from other variable or property in getter and update value back to things it computed in setter。 think about your property's character carefully。 mostly,you can directly readwrite computed property。 just remember it is function core and property skin

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM