Как вставлять функции в массив с помощью пользовательских опубликованных переменных
Вот желаемый результат (список из viewModel, полученный с использованием функций для ежегодного повышения заработной платы и отображения возраста пользователя из года в год). Когда пользователь изменяет дату своего рождения и дату приема на работу в ProfileFormView, этот список должен соответствующим образом обновить группу «Возраст и год»:
К сожалению, мне не удалось успешно создать это представление из-за ошибок при попытках включить функции в массив viewModel.
Вот моя модель просмотра:
class WorkerViewModel:ObservableObject {
@Published var userData: Worker =
Worker(name: "Robert", birthdate: Date(timeIntervalSince1970: 10000), hiredate: Date(timeIntervalSince1970: 30000), department: "HR")
func calcAge(birthdate: String) -> Int {
let dateFormater = DateFormatter()
dateFormater.dateFormat = "MM/dd/yyyy"
let birthdayDate = dateFormater.date(from: birthdate)
let calendar: NSCalendar! = NSCalendar(calendarIdentifier: .gregorian)
let now = Date()
let calcAge = calendar.components(.year, from: birthdayDate!, to: now, options: [])
let age = calcAge.year
return age!
}
func calcYearGroup(hiredate: String) -> Int {
let dateFormater = DateFormatter()
dateFormater.dateFormat = "MM/dd/yyyy"
let newHireDateFormatted = dateFormater.date(from: hiredate)
let calendar: NSCalendar! = NSCalendar(calendarIdentifier: .gregorian)
let now = Date()
let calcYearGroup = calendar.components(.year, from: newHireDateFormatted!, to: now, options: [])
let yearGroup = calcYearGroup.year! + 1
return yearGroup
}
func calcAnnualEarnings(hourlyRate: Double, monthlyHours: Double) -> Double {
return (hourlyRate * monthlyHours) * 12
}
@Published var userDataList: [WorkerInfo] = [
WorkerInfo(age: calcAge(birthdate: $WorkerInfo.birthdate), yearGroup: calcYearGroup(hiredate: $WorkerInfo.hiredate), salary: calcAnnualEarnings(hourlyRate: PayRates.hR[1], monthlyHours: 72), dept: "\($WorkerInfo.department)"),
WorkerInfo(age: calcAge(birthdate: $WorkerInfo.birthdate) + 1, yearGroup: calcYearGroup(hiredate: $WorkerInfo.hiredate) + 1, salary: calcAnnualEarnings(hourlyRate: PayRates.hR[2], monthlyHours: 72), dept: "\($WorkerInfo.department)"),
WorkerInfo(age: calcAge(birthdate: $WorkerInfo.birthdate) + 2, yearGroup: calcYearGroup(hiredate: $WorkerInfo.hiredate) + 2, salary: calcAnnualEarnings(hourlyRate: PayRates.hR[3], monthlyHours: 72), dept: "\($WorkerInfo.department)"),
WorkerInfo(age: calcAge(birthdate: $WorkerInfo.birthdate) + 3, yearGroup: calcYearGroup(hiredate: $WorkerInfo.hiredate) + 3, salary: calcAnnualEarnings(hourlyRate: PayRates.hR[4], monthlyHours: 72), dept: "\($WorkerInfo.department)"),
WorkerInfo(age: calcAge(birthdate: $WorkerInfo.birthdate) + 4, yearGroup: calcYearGroup(hiredate: $WorkerInfo.hiredate) + 4, salary: calcAnnualEarnings(hourlyRate: PayRates.hR[5], monthlyHours: 72), dept: "\($WorkerInfo.department)"),
]
}
Вот данные моей модели:
struct Worker: Codable, Identifiable {
var id = UUID()
var name: String
var birthdate: Date
var hiredate: Date
var department: String
}
struct WorkerInfo: Codable, Identifiable {
var id = UUID()
var age: Int
var yearGroup: Int
var salary: Double
var dept: String
}
struct MockData {
static let sampleUser = WorkerInfo(age: 41, yearGroup: 1, salary: 80000, dept: "HR")
}
struct PayRates {
let hR: [Double] = [0,92,128,150,154,158,162,166,170,172,174,177,180]
let management: [Double] = [0,235,236,238,240,242,244,246,248,250,252,254,256]
}
Вот мой вид контента:
struct ContentView: View {
@StateObject var vm = WorkerViewModel()
var body: some View {
TabView {
ProfileFormView()
.tabItem {
Image(systemName: "square.and.pencil")
Text("Profile")
}
WorkerView()
.tabItem {
Image(systemName: "house")
Text("Home")
}
.padding()
}.environmentObject(vm)
}
}
Вот мой рабочий вид:
struct WorkerView: View {
@EnvironmentObject var vm: WorkerViewModel
var body: some View {
ZStack {
List($vm.userDataList) { $worker in
WorkerCardView(workerInfo: $worker)
}
}
}
}
Вот мой вид ProfileForm:
struct ProfileFormView: View {
@EnvironmentObject var vm: WorkerViewModel
@State var depts = ["HR","Management","Marketing","Development"]
var body: some View {
Form {
Section(header: Text("Personal Information")) {
TextField("Name", text: $vm.userData.name)
DatePicker("Birthdate", selection: $vm.userData.birthdate, displayedComponents: .date)
DatePicker("New Hire Date", selection: $vm.userData.hiredate, displayedComponents: .date)
Picker("Department", selection: $vm.userData.department) {
ForEach(depts, id: \.self) {
Text ($0)
}
}
}
}
}
}
И, наконец, вот мой WorkerCard View:
struct WorkerCardView: View {
@Binding var workerInfo: WorkerInfo
var body: some View {
HStack{
VStack(alignment: .leading) {
Text("Year \(workerInfo.yearGroup)")
.font(.headline)
Label("Age \(workerInfo.age)", systemImage: "person")
.foregroundStyle(.blue)
.font(.subheadline)
}
Spacer()
VStack(alignment: .leading) {
Text("$ \(workerInfo.salary, specifier: "%.0f") salary")
.font(.headline)
Label("\(workerInfo.dept) Dept", systemImage: "building")
.foregroundStyle(.blue)
.font(.subheadline)
}
}
}
}
Заранее спасибо за вашу помощь!!
//ОБНОВЛЕНИЕ 1//
Я преобразовал свои функции в вычисляемые свойства, казалось бы, без ошибок. Это также имеет дополнительное преимущество, заключающееся в том, что код становится чище, что приятно.
Теперь я свел проблему к проблеме инициализации. Каждое из трех моих вычисляемых свойств вызывает ошибки компилятора при помещении в массив userDataList:
«Невозможно использовать член экземпляра 'computedProperty' в инициализаторе свойства; инициализаторы свойств запускаются до того, как становится доступным 'self'»
//ОБНОВЛЕНИЕ 2//
Я преобразовал userDataArray в вычисляемое свойство, но результирующая ошибка компилятора связана с оболочкой свойства @Published. Естественно, вычисляемые свойства не могут получать обертки свойств, но мне нужно, чтобы userDataArray был виден для WorkerView, чтобы список мог перебирать userDataArray.
Удаление @Published вызывает эту ошибку компилятора в WorkerView:
"Невозможно присвоить свойству: "userDataList" является свойством только для получения"