繁体   English   中英

从 SwiftUI ContentView 中的 @propertyWrapper 加载 json

[英]Load json from @propertyWrapper in SwiftUI ContentView

我一直在使用一个很好用的 json 解码实用程序。 我想知道是否可以将该实用程序抽象为接受 json 文件名作为字符串的 propertyWrapper。

ContentView 中的调用站点如下所示:

struct ContentView: View {
     @DataLoader("tracks.json") var tracks: [Tracks]
...

我对属性包装器的粗略草图如下所示:

@propertyWrapper 
struct DataLoader<T: Decodable>: DynamicProperty {
    private let fileName: String
    
    var wrappedValue: T {
        get {
            return Bundle.main.decode(T.self, from: fileName)
        }
        
        set {
             //not sure i need to set anything since i just want to get the array
        }
    }
    
    init(_ fileName: String) {
        self.fileName = fileName
        wrappedValue = Bundle.main.decode(T.self, from: fileName)
    }
}

当前 ContentView 的主体显示此错误:

未能产生表达诊断; 请提交错误报告

我喜欢删除一些样板代码的想法,但我认为我在这里遗漏了一些基本的东西。

在 SwiftUI 中,视图经常刷新。 当刷新视图时, @propertyWrapper将再次初始化 - 这可能是也可能不是可取的。 但值得注意的是。

这是一个简单的演示,展示了如何创建用于加载 JSON 文件的属性包装器。 为简单起见,我用try? fatalError但在实际代码中,您可能希望添加适当的错误处理。

@propertyWrapper
struct DataLoader<T> where T: Decodable {
    private let fileName: String

    var wrappedValue: T {
        guard let result = loadJson(fileName: fileName) else {
            fatalError("Cannot load json data \(fileName)")
        }
        return result
    }

    init(_ fileName: String) {
        self.fileName = fileName
    }

    func loadJson(fileName: String) -> T? {
        guard let url = Bundle.main.url(forResource: fileName, withExtension: "json"),
            let data = try? Data(contentsOf: url),
            let result = try? JSONDecoder().decode(T.self, from: data)
        else {
            return nil
        }
        return result
    }
}

然后,假设您有一个名为items.json的示例 JSON 文件:

[
    {
        "name": "Test1",
        "count": 32
    },
    {
        "name": "Test2",
        "count": 15
    }
]

具有相应的结构:

struct Item: Codable {
    let name: String
    let count: Int
}

您可以在视图中加载 JSON 文件:

struct ContentView: View {
    @DataLoader("items") private var items: [Item]

    var body: some View {
        Text(items[0].name)
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM