代码之家  ›  专栏  ›  技术社区  ›  Thingamajig

从Swift Decodables访问枚举的合适方法是什么?

  •  1
  • Thingamajig  · 技术社区  · 6 年前

    我有一个非常奇怪的例子,我使用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
        }
    }
    
    3 回复  |  直到 6 年前
        1
  •  1
  •   MadProgrammer    6 年前

    所以, 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 ,查找“关联值”部分

        2
  •  2
  •   Fabian    6 年前

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

    if case .galleryElementArray(let x) = imageArray[indexPath.row].acf.gallery {
        print(x.first!.id)
    }
    
        3
  •  2
  •   matt    6 年前

    但是一旦我到了acf画廊,它说.id不存在。这很奇怪

    不,不是。根据你的密码, .gallery 应该是厨房工会。嗯,厨房工会没有 .id .id号 ,但GalleryUnion不是GalleryElement。所以我不知道你的惊喜是从哪里来的,这里没有惊喜。

    厨房工会 案例 . 你需要检查一下这是哪种情况。如果是的话 . galleryElementArray 您需要提取关联的值。即使那样你也不会有 ,因为你现在所拥有的仍然不是一个厨房元素;这是一个 数组 厨房元素。

    通过使用一个额外的计算属性来定义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}
    

    …或者不管你想什么。