Я полный новичок в 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()
}
}
}
Проблема в том, что когда я меняю единицу измерения с британской на метрическую и возвращаюсь к просмотру сеанса, представление не обновляется, но когда я возвращаюсь к представлению тренировки и снова открываю представление сеанса, изменения уже есть.
Пожалуйста, дайте мне знать, если вам понадобится больше кода.
formattedWeight
функцию, которая принимает параметр massUnit и возвращает отформатированную строку? - person andre de waard   schedule 08.03.2021Text(session.formattedWeight)
? Как вы меняете предпочтения по отношению к просмотру сеанса; вы скажете, когда я вернусь к просмотру сеанса, как вы вернетесь? Вы представляете новое представление или возвращаетесь к существующему виду? - person Paulw11   schedule 08.03.2021@ObservedObject var userDefaultsWrapper = UserDefaultsWrapper()
в это представление. который я не использую, но он обновляет представление. - person andre de waard   schedule 08.03.2021