iOS swift Codable 无法与 Alamofire 一起使用 JSON 嵌套数据?

Cod*_*e92 3 ios swift alamofire codable

我对 iOS 中的 Alamofire 和 Codable 概念不熟悉,有人可以告诉我如何使用它来访问我的 json 数据。

这是我的 json 响应。

{"subscriptions": [
        {
            "batch_user_id": 23,
            "batch_name": "demo batch",
            "course_name": "IELTS",
            "start_date": "Nov 01 2019",
            "end_date": "Nov 30 2019",
            "no_of_days": 21,
            "total_no_of_days": 30,
            "extended_date": "Nov 30 2019",
            "extended": false,
            "course_extensions": [
                {
                    "id": 31,
                    "amount": "3500.0",
                    "course_id": 1,
                    "is_active": true,
                    "number_of_days": 5
                },
Run Code Online (Sandbox Code Playgroud)

这是可编码的代码:

 struct course_extensions: Codable {
        let id: String
        let amount: String
        let course_id: String

        private enum CodingKeys: String, CodingKey {
            case id = "id"
            case amount = "amount"
            case course_id = "course_id"
        }
    }

    struct subscriptions: Codable {
        let batch_user_id: String
        let batch_name: String
        let course_extensions: course_extensions

        private enum CodingKeys: String, CodingKey {
            case batch_user_id
            case batch_name
            case course_extensions = "course_extensions"
        }
    }
    struct User: Codable {
        let status: String
        let message: String
        let subscriptions: subscriptions
    }
Run Code Online (Sandbox Code Playgroud)

这是我与 alamofire 的服务调用:

// MARK: - Service call

func fetchUserData() {
    AF.request(SMAConstants.my_subscriptions, method: .get, parameters: nil, headers: nil)
        .responseJSON { (response) in
            switch response.result {
            case .success(let value):
                let swiftyJsonVar = JSON(value)
                print(swiftyJsonVar)
            case .failure(let error):
                print(error)

            }
    }
}
Run Code Online (Sandbox Code Playgroud)

有人可以帮助我使用 codable 访问嵌套数组数据吗?提前致谢。

Rob*_*Rob 6

您\xe2\x80\x99 缺少 JSON 最外层部分的结构:

\n\n
struct ResponseObject: Codable {\n    let subscriptions: [Subscription]\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且,您可以使用普通的驼峰命名法属性:

\n\n
struct Subscription: Codable {\n    let batchUserId: Int\n    let batchName: String\n    let courseExtensions: [CourseExtension]\n}\n\nstruct CourseExtension: Codable {\n    let id: Int\n    let amount: String\n    let courseId: Int\n    let isActive: Bool\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

一些观察:

\n\n
    \n
  • struct按照惯例,类型名称应以大写字母开头。
  • \n
  • 在这种情况下,这些CodingKeys都是不必要的。
  • \n
  • 小心你的类型。其中一些是IntBoolString仅当值包含在引号中时才使用 类型。
  • \n
  • 显然,为了简洁起见,我\xe2\x80\x99从上述类型中排除了一些属性struct,但添加了任何缺失的属性,但坚持驼峰命名约定。
  • \n
\n\n

不管怎样,你可以告诉解码器使用以下命令将snake_case JSON键转换为camelCase属性名称:

\n\n
do {\n    let decoder = JSONDecoder()\n    decoder.keyDecodingStrategy = .convertFromSnakeCase\n\n    let object = try decoder.decode(ResponseObject.self, from: data)\n    print(object.subscriptions)\n} catch {\n    print(error)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

例如,如果使用 Alamofire 5:

\n\n
let decoder: JSONDecoder = {\n    let decoder = JSONDecoder()\n    decoder.keyDecodingStrategy = .convertFromSnakeCase\n    return decoder\n}()\n\nfunc fetchUserData() {\n    AF.request(SMAConstants.mySubscriptions))\n        .responseDecodable(of: ResponseObject.self, decoder: decoder) { response in\n            guard let value = response.value else {\n                print(response.error ?? "Unknown error")\n                return\n            }\n\n            print(value.subscriptions)\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这产生了:

\n\n
[Subscription(batchUserId: 23, batchName: "demo batch", courseExtensions: [CourseExtension(id: 31, amount: "3500.0", courseId: 1, isActive: true)])]\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

顺便说一句,我注意到您的日期格式为MMM d yyyy. 您想将它们转换为Date对象吗?如果是这样,您可以使用指定日期格式化程序的解码器,如下所示:

\n\n
let decoder: JSONDecoder = {\n    let decoder = JSONDecoder()\n\n    decoder.keyDecodingStrategy = .convertFromSnakeCase\n\n    let formatter = DateFormatter()\n    formatter.locale = Locale(identifier: "en_US_POSIX")\n    formatter.dateFormat = "MMM d yyyy"\n    decoder.dateDecodingStrategy = .formatted(formatter)\n\n    return decoder\n}()\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后你可以定义startDateendDateDate对象。然后,当您在 UI 中呈现这些日期时,您可以使用 aDateFormatter来显示日期的良好本地化呈现,而不仅仅是固定的、丑陋的MMM d yyyy格式。

\n\n

要在 UI 中显示日期,您\xe2\x80\x99d 然后执行以下操作:

\n\n
let dateFormatter: DateFormatter = {\n    let formatter = DateFormatter()\n    formatter.dateStyle = .medium\n    return formatter\n}()\n
Run Code Online (Sandbox Code Playgroud)\n\n

进而:

\n\n
label.text = dateFormatter.string(from: date)\n
Run Code Online (Sandbox Code Playgroud)\n\n

在美国说英语的人会看到:

\n\n
\n

2019 年 4 月 15 日

\n
\n\n

居住在美国的西班牙语使用者将会看到:

\n\n
\n

缩写。2019 年 15 日

\n
\n\n

在西班牙讲西班牙语的人会看到:

\n\n
\n

2019 年 4 月 15 日

\n
\n\n

最重要的是,用户将以他们期望的格式看到日期,而不是以某种特定的美国英语格式硬编码。您还可以选择使用.long空间允许的格式(例如 \xe2\x80\x9cApril 15, 2019\xe2\x80\x9d)或.short\xe2\x80\x99 空间非常紧张的格式(例如 \xe2\x80\ x9c04/15/19\xe2\x80\x9d)。只需选择dateStyle适合您特定需求的即可。

\n