0

我正在学习 SwiftUI。我从做 Apple SwiftUI 教程开始。在其中一个中,他们提供了@EnviromentalObjects 来更改他们的模型,他们正在改变isFavorite bool 状态。但是他们没有将@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 文件中加载数据(从苹果教程复制)

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)
                }
            }

我试图在 UserDefault.standard.object 中嵌入 CityData,但它没有用。我肯定做错了什么。你能帮助我吗?

我的带有城市列表和 isFavorite Toggle 的应用

4

1 回答 1

0

SwiftUI@Published对于您想要做的事情还不够聪明。

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

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

于 2019-12-01T23:04:52.830 回答