我正在try 快速解码一个JSON字符串,但在解码后访问属性时遇到了一些奇怪的问题.

这是我从本地存储的JSON文件中检索的JSON文件的内容

[
  {
    "word": "a",
    "usage": [
      {
        "partOfSpeech": "determiner"
      }
    ]
  }
]

这是访问JSON文件属性的代码

struct WordDictionary : Codable {
    var word: String
    var usage: [Usage]
}

struct Usage: Codable {
    var partOfSpeech: String
}
                
if let url = Bundle.main.url(forResource: FILE_NAME, withExtension: "json") {
    do {
        let data = try Data(contentsOf: url)
        let decoder = JSONDecoder()
        
        let jsonData = try decoder.decode([WordDictionary].self, from: data)
        print(jsonData[0].word) //Outputs "a"
        print(jsonData[0].usage) //Outputs "[MyApp.AppDelegate.(unknown context at $102a37f00).(unknown context at $102a38038).Usage(partOfSpeech: "determiner")]"

    } catch {
        print("error:\(error)")
    }
}

正如您所看到的,当我try 使用print(jsonData[0].usage)时,在获得"Usage"属性之前,我得到了一系列未知的数据消息.当我打印这一行时,我只想看到determiner,我不确定关于"未知背景"的序言是什么意思.

我也在AppDelegatedidFinishLaunchingWithOptions函数中运行这段代码.

我不确定我错过了什么.几天来,我一直在努力寻找解决方案,try 了不同的方法,但仍然无法获得所需的输出,任何帮助都将不胜感激.

推荐答案

TL;DR

您在该类型的描述中看到了"未知上下文",因为它是在函数中定义的.您可以通过将这些类型定义移到函数外部或实现您自己的CustomStringConvertible一致性来解决这个问题.


这是在哪里定义类型的问题.

请考虑:

class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        struct WordDictionary: Codable {
            var word: String
            var usage: [Usage]
        }

        struct Usage: Codable {
            var partOfSpeech: String
        }

        do {
            let url = Bundle.main.url(forResource: "test", withExtension: "json")!
            let data = try Data(contentsOf: url)
            let words = try JSONDecoder().decode([WordDictionary].self, from: data)
            print(words[0].usage)
        } catch {
            print(error)
        }

        return true
    }

    ...
}

这会产生以下结果:

[MyApp.AppDelegate.($102bac454处的未知上下文).($102bac58c处的未知上下文).Usage(partOfSpeech:"Definer")]

这就是说,Usage是在MyApp内的AppDelegate内的某个未知的上下文中定义的.简而言之,它不知道如何表示函数中定义的类型的层次 struct .

与此形成对比的是:

class AppDelegate: UIResponder, UIApplicationDelegate {

    struct WordDictionary: Codable {
        var word: String
        var usage: [Usage]
    }

    struct Usage: Codable {
        var partOfSpeech: String
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        do {
            let url = Bundle.main.url(forResource: "test", withExtension: "json")!
            let data = try Data(contentsOf: url)
            let words = try JSONDecoder().decode([WordDictionary].self, from: data)
            print(words[0].usage)
        } catch {
            print(error)
        }

        return true
    }

    ...
}

这将产生:

[MyApp.AppDelegate.Usage(partOfSpeech:"Definer")]


您还可以添加您自己的CustomStringConvertible一致性:

struct WordDictionary: Codable {
    var word: String
    var usage: [Usage]
}

struct Usage: Codable {
    var partOfSpeech: String
}

extension Usage: CustomStringConvertible {
    var description: String { "Usage(partOfSpeech: \"\(partOfSpeech)\")" }
}

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        do {
            let url = Bundle.main.url(forResource: "test", withExtension: "json")!
            let data = try Data(contentsOf: url)
            let words = try JSONDecoder().decode([WordDictionary].self, from: data)
            print(words[0].usage)
        } catch {
            print(error)
        }

        return true
    }

    ...
}

这将产生:

[用法(partOfSpeech:"Definer")]

通过CustomStringConvertible,您可以随心所欲地设置print格式.

Ios相关问答推荐

SwiftUI绑定到特定的一个或多个枚举 case

SwiftUI-工作表不显示导航标题

如何使用 SwiftData 从列表中删除子项目?

Flutter应用内购买无法恢复购买

iOS设备网页自动化中,在向字段发送文本后未启用按钮

表视图(SwiftUI)中的多列?

为什么这个 init 被分派到一个内部扩展 init?

Swift Combine:prepend() before share() 阻止初始接收器执行

Swift 5.7 - 使存在的任何协议符合 Hashable

我可以在 Apple-Watch 上使用 iPhone 的摄像头扫描 SwiftUi 中的二维码(例如用于登录)吗

如何识别 SwiftUI 中点击的按钮 ID 以使该按钮动画化?

使用 CIImage 支持的 UIImage 设置 UIImageView 时发生罕见的崩溃

判断Apple LiveText是否可用?

iOS swift从另一个数组中删除一个数组的元素

如何从一个特定的视图控制器中隐藏导航栏

刷新由 Xcode 7 管理的团队配置文件中的设备?

在 Xcode 4 中将静态库链接到 iOS 项目

如何识别导航堆栈中的前一个视图控制器

AFNetworking 2.0 向 GET 请求添加标头

如何为 NSDate 添加一个月?