【问题标题】:What's the appropriate way to access an enum from Swift Decodables?从 Swift Decodables 访问枚举的适当方法是什么?
【发布时间】:2018-09-16 01:42:31
【问题描述】:

我有一个非常奇怪的案例,我使用 JSON 并认为我可以将子字符串一直插入到我想要访问的数据,但是,它没有按预期工作。

使用 QuickType,我能够转换这个 JSON:https://kidsuper.fodalabs.com/wp-json/wp/v2/art

到下面。

当我尝试访问时,似乎我应该能够做到.acf.gallery.id 但是一旦我到达acf.gallery,它就会说.id 不存在。这很奇怪,但这是我尝试时返回的结果

let temp = imageArray[indexPath.row].acf.gallery.id
Value of type 'GalleryUnion?' has no member 'id'

只是为了好玩,我尝试了这个,但也没有运气:

let temp = imageArray[indexPath.row].acf.GalleryUnion.galleryElementArray
    Error

:“Acf”类型的值没有成员“GalleryUnion”

我打印.acf.gallery 时的返回是这样开始的:

Acf(company: "Season #3", 
     gallery: Optional(weddingszn.GalleryUnion.galleryElementArray([weddingszn.GalleryElement(
         id: 135, galleryID: 135, title: "1-791x1024", 
         filename: "1-791x1024.jpg", url: "https://kidsuper.fodalabs.com/wp-content/up

下面是我要解析的完整代码。有任何想法吗?

struct Acf: Codable {
    let company: String
    let gallery: GalleryUnion?
    let tagline: String
    let featuredImg: Bool?

    enum CodingKeys: String, CodingKey {
        case company, gallery, tagline
        case featuredImg = "featured_img"
    }
}

enum GalleryUnion: Codable {
    case bool(Bool)
    case galleryElementArray([GalleryElement])

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(Bool.self) {
            self = .bool(x)
            return
        }
        if let x = try? container.decode([GalleryElement].self) {
            self = .galleryElementArray(x)
            return
        }
        throw DecodingError.typeMismatch(GalleryUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for GalleryUnion"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .bool(let x):
            try container.encode(x)
        case .galleryElementArray(let x):
            try container.encode(x)
        }
    }
}

struct GalleryElement: Codable {
    let id, galleryID: Int
    let title, filename: String
    let url: String
    let alt, author, description, caption: String
    let name, date, modified: String
    let mimeType: MIMEType
    let type: TypeEnum
    let icon: String
    let width, height: Int
    let sizes: Sizes

    enum CodingKeys: String, CodingKey {
        case id = "ID"
        case galleryID = "id"
        case title, filename, url, alt, author, description, caption, name, date, modified
        case mimeType = "mime_type"
        case type, icon, width, height, sizes
    }
}

【问题讨论】:

  • 不应该是acf.GalleryUnionacf. gallery
  • 是的,我都试过了,结果一样

标签: ios json swift api quicktype


【解决方案1】:

在深入到数组之前,您必须使用 if case、guard case 或 switch case 来解压枚举。

if case .galleryElementArray(let x) = imageArray[indexPath.row].acf.gallery {
    print(x.first!.id)
}

【讨论】:

  • 冠军!非常感谢!
【解决方案2】:

但是,一旦我进入 acf.gallery,它就会说 .id 不存在。这很奇怪

不,不是。根据您的代码,.gallery 应该是 GalleryUnion。好吧,GalleryUnion 没有.id。它根本没有任何属性。 GalleryElement 具有.id,但 GalleryUnion 不是 GalleryElement。所以我看不出你的惊喜来自哪里;这里没有惊喜。

GalleryUnion 有案例。您需要检查这是哪种情况。如果是. galleryElementArray,则需要提取关联值。即使那样,您也不会拥有任何.id,因为您现在拥有的仍然不是 GalleryElement;它是 GalleryElements 的 array

您可以通过使用额外的计算属性为您获取相关值来定义 GalleryUnion,从而使您自己更轻松:

enum GalleryUnion : Codable {
    case bool(Bool)
    case galleryElementArray([GalleryElement])
    var galleryElements : [GalleryElement]? {
        switch self {
        case .bool : return nil
        case let .galleryElementArray(arr): return arr
        }
    }
    // ... and so on
}

这至少可以让你说:

act.gallery.galleryElements?.map {$0.id}

...或者任何你想到的东西。

【讨论】:

  • 展示了如何在一行中向下钻取和提取关联值 inline,更像是您最初尝试使用的代码。
【解决方案3】:

所以,GalleryUnion 可以是两件事之一。它既可以是.bool(_),也可以是galleryElementArray(_)。当您想要访问实际的底层价值时,您需要确定它处于哪个状态。

要在 Swift 中执行此操作,您可以使用 switch 语句。然后,您可以使用它来访问内部包含的值。也许类似于:

if let gallery = acf.gallery {
    switch gallery {
    case .galleryElementArray(let values):
        values.forEach {
            print($0.id)
        }
    case .bool(_):
        break
    }
}

您可能想阅读Enumerations,查找“关联值”部分

【讨论】:

    猜你喜欢
    • 2018-01-09
    • 2020-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多