模型中的UserDefaults的SwiftUI问题

时间:2019-12-01 22:41:11

标签: swiftui userdefaults observedobject

我正在学习SwiftUI。我从编写Apple SwiftUI教程开始。在其中之一中,他们提供了@EnviromentalObjects来更改其模型,它们正在更改 isFavorite 布尔状态。 但是他们没有将 @ObservedObject与UserDefaults一起使用,并且当我重新加载我的应用程序时,所有更改都无法使用。我已经学习了如何使用 UserDefaults 作为视图中的值,现在,如果我只想显示 isFavorive 对象或全部对象,以及何时显示它们,就可以在对象列表中进行设置我重新加载了应用程序,此切换按钮正在保存我的更改。

但是我想对模型进行编辑。

有我的模特:

import SwiftUI
import CoreLocation

struct City: Hashable, Codable, Identifiable {
var id: Int
var country: String
var name: String
var description: String
fileprivate var imageName: String
fileprivate var coordinates: Coordinates
var state: String
var people: Int
var area: Int
var continent: Continent
var isFavorite: Bool
var isFeatured: Bool


var locationCoordinate: CLLocationCoordinate2D {
    CLLocationCoordinate2D(
        latitude: coordinates.latitude,
        longitude: coordinates.longitude)
}

enum Continent: String, CaseIterable, Codable, Hashable {
    case europe = "Europe"
    case asia = "Asia"
    case america = "America"
}
}

有一个文件,我可以从JSON文件中加载数据(从Apple教程复制)

import UIKit
import SwiftUI
import CoreLocation

var CityData: [City] = load("CityData.json")

func load<T: Decodable>(_ filename: String) -> T {
let data: Data

guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
    else {
        fatalError("Couldn't find \(filename) in main bundle.")
}

do {
    data = try Data(contentsOf: file)
} catch {
    fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
}

do {
    let decoder = JSONDecoder()
    return try decoder.decode(T.self, from: data)
} catch {
    fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
}
}


final class ImageStore {
typealias _ImageDictionary = [String: CGImage]
fileprivate var images: _ImageDictionary = [:]

fileprivate static var scale = 2

static var shared = ImageStore()

func image(name: String) -> Image {
    let index = _guaranteeImage(name: name)

    return Image(images.values[index], scale: CGFloat(ImageStore.scale), label: Text(verbatim: name))
}

static func loadImage(name: String) -> CGImage {
    guard
        let url = Bundle.main.url(forResource: name, withExtension: "jpg"),
        let imageSource = CGImageSourceCreateWithURL(url as NSURL, nil),
        let image = CGImageSourceCreateImageAtIndex(imageSource, 0, nil)
    else {
        fatalError("Couldn't load image \(name).jpg from main bundle.")
    }
    return image
}

fileprivate func _guaranteeImage(name: String) -> _ImageDictionary.Index {
    if let index = images.index(forKey: name) { return index }

    images[name] = ImageStore.loadImage(name: name)
    return images.index(forKey: name)!
}
}

在这里您可以看到CityData的使用方式:

**%% in UserData.swift file %%**

final class UserData: ObservableObject {
@Published var city = CityData
}

**%And in my view %%**

struct CityList: View {
@EnvironmentObject private var userData: UserData
@ObservedObject var SettingsVM = SettingsViewModel()

var body: some View {
    NavigationView {
        List {
            Toggle(isOn: $SettingsVM.showFavoritesOnly) {
                Text("Show Favorites Only")
            }

            ForEach(userData.city) { City in
                if !self.SettingsVM.showFavoritesOnly || City.isFavorite {
                    NavigationLink(
                        destination: ContentView(city: City)
                            .environmentObject(self.userData)
                    )
                    {
                        CityRow(city: City)
                    }
                }
            }
        }
        .navigationBarTitle(Text("Capitals"))
    }
}
}

%%以及我如何更改“ isFavorite”值

   Button(action: {
                self.userData.city[self.cityIndex].isFavorite.toggle();
                print(String(self.city.isFavorite));

            }) {
                if self.userData.city[self.cityIndex].isFavorite {
                    Image(systemName: "star.fill")
                        .foregroundColor(Color.yellow)
                } else {
                    Image(systemName: "star")
                        .foregroundColor(Color.gray)
                }
            }

我试图将CityData嵌入UserDefault.standard.object中,但是没有用。我肯定是在做错事。你能帮我吗?

My app with City List and isFavorite Toggle

1 个答案:

答案 0 :(得分:0)

SwiftUI的@Published不够智能,无法满足您的需求。

您正在将@Published与数组一起使用。但是您以后不会分配给数组,您只需访问它的一个元素并对其进行修改。 @Published从未看到更改,因为未分配发布变量。因此,不会触发任何重新渲染。

在更改数组元素以触发重新渲染之前,请调用self.userData.objectWillChange.send()