微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 UserDefaults 更新上更新 swiftUI 视图

如何解决在 UserDefaults 更新上更新 swiftUI 视图

我完全是 Swift 和 SwiftUI 的菜鸟,我正在尝试为自己构建一个项目,在那里我可以跟踪我的锻炼并学习一些 Swift。 我遇到的问题是,我有一个视图显示我的所有锻炼课程,并由我在 UserDefaults 中的设置进行格式化。用户可以将此设置更改为“公制”或“英制” 更改此项时,视图应更新以表示这些更改。

我拥有的数据是:

extension WorkoutSession {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<WorkoutSession> {
        return NSFetchRequest<WorkoutSession>(entityName: "WorkoutSession")
    }

    @NSManaged public var created_at: Date?
    @NSManaged public var id: UUID?
    @NSManaged public var reps: Int16
    @NSManaged public var sets: Int16
    @NSManaged public var updated_at: Date?
    @NSManaged public var weight: Double
    @NSManaged public var height: Double
    @NSManaged public var notes: String?
    @NSManaged public var type: Workout?

    override public func awakeFromInsert() {
        super.awakeFromInsert()
        setPrimitiveValue(UUID(),forKey: "id")
        setPrimitiveValue(Date(),forKey: "updated_at")
    }
    
    override public func willSave() {
        super.willSave()
        if let updated_at = updated_at {
            if updated_at.timeIntervalSince(Date()) > 10.0 {
                self.updated_at = Date()
            }

        } else {
            self.updated_at = Date()
        }
    }
    
    var formattedWeight: String {
        var measurement = Measurement(value: self.weight,unit: UserDefaultsWrapper().savedUnitWeight)
        let numberFormatter = NumberFormatter()
        let measurementFormatter = MeasurementFormatter()
        measurement.convert(to:UserDefaultsWrapper().getWeightUnit)
        numberFormatter.maximumFractionDigits = 2
        measurementFormatter.unitOptions = .providedUnit
        measurementFormatter.numberFormatter = numberFormatter
        return measurementFormatter.string(from: measurement)
    }
    
    
    // No matter the user defined weight we always save the values in Kilogram so we can convert to anything afterwards
    func convertWeightFromUserDefinedUnitToKilogram(weight: Double) -> Double {
        let measurement = Measurement(value: weight,unit: UserDefaultsWrapper().getWeightUnit)
        return measurement.converted(to: UserDefaultsWrapper().savedUnitWeight).value
    }
    
}

extension WorkoutSession : Identifiable {

}

我还让自己成为 userDefaults 的帮手

import SwiftUI
import Foundation

enum UserDefaultsKeys: String {
    case measurementUnit = "measurementUnit"
}

enum measurementUnit: String,CaseIterable {
    case metric = "metric"
    case imperial = "Imperial"
}


struct UserDefaultsWrapper {
    let defaults = UserDefaults.standard
    
    var savedUnitWeight = UnitMass.kilograms
    var savedUnitHeight = UnitLength.meters
    
    @AppStorage(UserDefaultsKeys.measurementUnit.rawValue) var selectedUnit: String = measurementUnit.metric.rawValue
    
    var getMeasurementUnit: measurementUnit {
        get {
            let locale = Locale.current
            let systemMeasurementUnit = locale.usesMetricSystem ? measurementUnit.metric : measurementUnit.imperial
            return measurementUnit(rawValue: selectedUnit) ?? systemMeasurementUnit
        }
        set(unit) {
            defaults.set(unit.rawValue,forKey: UserDefaultsKeys.measurementUnit.rawValue)
        }
    }

    var getWeightUnit: UnitMass {
        switch getMeasurementUnit {
            case measurementUnit.imperial:
                return UnitMass.pounds
            case measurementUnit.metric:
                fallthrough
            default:
                return UnitMass.kilograms
        }
    }
    
    var getHeightUnit: UnitLength {
        switch getMeasurementUnit {
            case measurementUnit.imperial:
                return UnitLength.feet
            case measurementUnit.metric:
                fallthrough
            default:
                return UnitLength.meters
        }
    }


}

这是风景

import SwiftUI

struct WorkoutDetailView: View {
    
    @Environment(\.managedobjectContext) var moc
    
    @State private var showingAddWorkoutView = false
    
    @Observedobject var workout: Workout
    
    var body: some View {
        List {
            ForEach(workout.sessionsArray,id: \.id) { session in
                Text("\(session.formattedWeight)")
            }
            .onDelete(
                perform: { offsets in
                    self.removeItems(at: offsets,from: workout)
                }
            )
        }
        .listStyle(InsetGroupedListStyle())
        .navigationTitle(workout.name ?? "UnkNown Workout")
        .navigationBarItems(
            leading: EditButton(),trailing:
                Button(action: {
                    self.showingAddWorkoutView = true
                }) {
                    Image(systemName: "plus")
                }
        )
        .sheet(isPresented: $showingAddWorkoutView) {
            AddWorkoutSession(workout: workout)
                .environment(\.managedobjectContext,moc)
        }
    }
    
    func removeItems(at offsets: IndexSet,from workout: Workout) {
        for offset in offsets {
            let sessionToDelete = workout.sessionsArray[offset]
            workout.removeFromSessions(sessionToDelete)
            moc.delete(sessionToDelete)
        }
        if moc.hasChanges{
            try? moc.save()
        }
    }
}

问题是,当我将单位从英制更改为公制并返回会话视图时,视图未更新,但是当我返回锻炼视图并再次打开会话视图时,更改就在那里。

如果您需要更多代码,请告诉我。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。