如何在切换SwiftUI中使用json属性?

如何在切换SwiftUI中使用json属性?,json,swiftui,toggle,Json,Swiftui,Toggle,我尝试动态编程一个切换,以在我的SwiftUI项目中显示一个较短的列表 我使用的JSON文件是。 我的项目正在进行中 我像这样编程切换,但当我打开它时,它不会显示正确的列表。目标是将JSON isShow属性链接到toggle属性。禁用切换时,将显示完整列表;启用切换时,仅显示isShow=FALSE列表 ForEach(0..<self.userData.movies.filter{ self.showShowOnly == true ? $0.isShow == self.showS


我尝试动态编程一个切换,以在我的SwiftUI项目中显示一个较短的列表

我使用的JSON文件是。
我的项目正在进行中

我像这样编程切换,但当我打开它时,它不会显示正确的列表。目标是将JSON isShow属性链接到toggle属性。禁用切换时,将显示完整列表;启用切换时,仅显示isShow=FALSE列表

ForEach(0..<self.userData.movies.filter{ self.showShowOnly == true ?  $0.isShow == self.showShowOnly  : true }.count, id: \.self) { movieIndex in
                        VStack (alignment: .leading) {
                            NavigationLink(destination: ContentView(movie: self.$userData.movies[movieIndex])) {
                                Text(self.userData.movies[movieIndex].nom)
                            }

                        }}

json获取程序是:

public class MovieFetcher: ObservableObject {
func save(movies: [Movie]) {

    OperationQueue().addOperation {

        do {
            let encoded = try JSONEncoder().encode(movies)
            let url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

            do {
                try encoded.write(to: url[0].appendingPathComponent("movies"))
                print("saved to ", url[0])
            } catch {
                print(error)
            }

        } catch {
            print(error)
        }
    }
}

func load(completion: @escaping (([Movie]?) -> () )) {

    let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

    do {
        if let data = try? Data(contentsOf: urls[0].appendingPathComponent("movies")) {

            let decodedLists = try JSONDecoder().decode([Movie].self, from: data as Data)
            DispatchQueue.main.async {
                completion(decodedLists)
            }


        } else {
            loadFromJson(completion: completion)
        }
    } catch {
        print(error)
        completion(nil)
    }
}

func loadFromJson(completion: @escaping (([Movie]?) -> () )) {

    let url = URL(string: "https://gist.githubusercontent.com/thomjlg/0782e9e8e27c346af3600bff9923f294/raw/9705fb0c6b40eae59578755b86e331bea257972b/films2.json")!

    URLSession.shared.dataTask(with: url) {(data,response,error) in
        do {
            if let d = data {
                let decodedLists = try JSONDecoder().decode([Movie].self, from: d)
                DispatchQueue.main.async {
                    completion(decodedLists)
                }
            }else {
                print("No Data")
                completion(nil)
            }
        } catch {
            print ("Error")
            completion(nil)
        }

    }.resume()
}
}

有人知道如何更正我的代码吗?
谢谢

如果我正确理解了您的问题,您希望调整过滤器。如果正确,请尝试此筛选器:

ForEach(0..<self.userData.movies.filter{ self.showShowOnly ? $0.isShow == !self.showShowOnly : true }.count, id: \.self)

ForEach(0..过滤代码有效。请注意,323部电影中只有1部电影的“isShow”为true

  "nom":"Ratatouille",
        "id":217,
        "idL":"R",
        "note":0,
        "isShow":true
问题在于在ForEach循环中使用“movieIndex”的方式。“movieIndex”指的是过滤后的self.userData.movies列表的索引。此“movieIndex” 不应在self.userData.movies[movieIndex]中使用

要解决此问题,请执行以下操作:

                    ForEach(self.userData.movies.filter{ self.showShowOnly ? $0.isShow == !self.showShowOnly : true }) { movie in
                        VStack (alignment: .leading) {
                            NavigationLink(destination: ContentView(movie: movie)) {
                                Text(movie.nom)
                            }
                        }
                    } 
试试这个,让我知道这是否有效

编辑:为电影而不是结构尝试此类

open class Movie: Codable, Identifiable, Equatable, Hashable, ObservableObject {

@Published public var id: Int
@Published public var nom: String
@Published public var idL: String
@Published public var note: Int
@Published public var isShow: Bool

enum CodingKeys: String, CodingKey {
    case id = "id"
    case nom = "nom"
    case idL = "idL"
    case note = "note"
    case isShow = "isShow"
}

public static func == (lhs: Movie, rhs: Movie) -> Bool {
    lhs.id == rhs.id
}

public func hash(into hasher: inout Hasher) {
    hasher.combine(id)
}

public init(id: Int, nom: String, idL: String, note: Int, isShow: Bool) {
    self.id = id
    self.nom = nom
    self.idL = idL
    self.note = note
    self.isShow = isShow
}

public init() {
    self.id = UUID().hashValue
    self.nom = ""
    self.idL = ""
    self.note = 0
    self.isShow = false
}

public required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.id = try container.decode(Int.self, forKey: .id)
    self.nom = try container.decode(String.self, forKey: .nom)
    self.idL = try container.decode(String.self, forKey: .idL)
    self.note = try container.decode(Int.self, forKey: .note)
    self.isShow = try container.decode(Bool.self, forKey: .isShow)
}

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(id, forKey: .id)
    try container.encode(nom, forKey: .nom)
    try container.encode(idL, forKey: .idL)
    try container.encode(note, forKey: .note)
    try container.encode(isShow, forKey: .isShow)
}
}

注意:您必须在ContentView中将“@Binding var movie:movie”更改为“@ObservedObject var movie:movie”,并调整“ContentView\u预览”“

谢谢你的回答,你是对的,这就是我想要的!我尝试了你的答案,但当我测试时,我发现它不起作用…我想这是因为它是指向JSON文件的链接,但我有可能更改每部电影的isShow值…这在userData中是可能的…你知道为什么你的答案不起作用吗?”?(你可以在GitHub上下载我的项目并进行测试,我在其中添加了代码行)注意,电影是一个结构,你不能像在ContentView中那样更改它的值,使用类来代替它,或者更好地使用类ObservieObject。谢谢你的回答。我不知道如何调整
ContentView\u预览
…我尝试了
菜单(电影:电影)
但它不起作用。我还必须更改SceneDelegate.swift文件中的
菜单()
在ContentView中的预览只需执行以下操作:“ContentView(电影:电影(id:1,nom:A),idL:B,注意:2,isShow:true),注意:3)”您不必更改SceneDelegate.swiftc电影中的菜单()。
open class Movie: Codable, Identifiable, Equatable, Hashable, ObservableObject {

@Published public var id: Int
@Published public var nom: String
@Published public var idL: String
@Published public var note: Int
@Published public var isShow: Bool

enum CodingKeys: String, CodingKey {
    case id = "id"
    case nom = "nom"
    case idL = "idL"
    case note = "note"
    case isShow = "isShow"
}

public static func == (lhs: Movie, rhs: Movie) -> Bool {
    lhs.id == rhs.id
}

public func hash(into hasher: inout Hasher) {
    hasher.combine(id)
}

public init(id: Int, nom: String, idL: String, note: Int, isShow: Bool) {
    self.id = id
    self.nom = nom
    self.idL = idL
    self.note = note
    self.isShow = isShow
}

public init() {
    self.id = UUID().hashValue
    self.nom = ""
    self.idL = ""
    self.note = 0
    self.isShow = false
}

public required init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.id = try container.decode(Int.self, forKey: .id)
    self.nom = try container.decode(String.self, forKey: .nom)
    self.idL = try container.decode(String.self, forKey: .idL)
    self.note = try container.decode(Int.self, forKey: .note)
    self.isShow = try container.decode(Bool.self, forKey: .isShow)
}

public func encode(to encoder: Encoder) throws {
    var container = encoder.container(keyedBy: CodingKeys.self)
    try container.encode(id, forKey: .id)
    try container.encode(nom, forKey: .nom)
    try container.encode(idL, forKey: .idL)
    try container.encode(note, forKey: .note)
    try container.encode(isShow, forKey: .isShow)
}
}