如何手动对选定的按键进行解码,以及如何使用快速解码功能自动解码呢?

时间:2019-07-26 07:55:55

标签: ios swift codable decodable encodable

这是我正在使用的代码,

//Your path here.
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/example.pdf";
File file = new File(path);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/pdf");
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);

此处,File file = new File(uri.getPath()); struct CreatePostResponseModel : Codable{ var transcodeId:String? var id:String = "" enum TopLevelCodingKeys: String, CodingKey { case _transcode = "_transcode" case _transcoder = "_transcoder" } enum CodingKeys:String, CodingKey{ case id = "_id" } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: TopLevelCodingKeys.self) if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcode) { self.transcodeId = transcodeId }else if let transcodeId = try container.decodeIfPresent(String.self, forKey: ._transcoder) { self.transcodeId = transcodeId } } } transcodeId决定。 但是我希望_transcode和其余的键(此处未包括)被自动解码。我该怎么办?

3 个答案:

答案 0 :(得分:1)

一旦以init(from:)类型实现Codable,就需要手动解析所有键。

struct CreatePostResponseModel: Decodable {
    var transcodeId: String?
    var id: String

    enum CodingKeys:String, CodingKey{
        case id, transcode, transcoder
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeIfPresent(String.self, forKey: .id) ?? ""
        if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcode) {
            self.transcodeId = transcodeId
        } else if let transcodeId = try container.decodeIfPresent(String.self, forKey: .transcoder) {
            self.transcodeId = transcodeId
        }
    }
}

在上面的代码中,

  1. 如果您只想解码 JSON ,则无需使用Codable。使用Decodable就足够了。
  2. 这里enums使用多个CodingKey似乎是不必要的。您可以使用一个enum CodingKeys
  3. 如果属性名称密钥名称完全匹配,则无需显式指定该rawValue的{​​{1}}在case中。因此,enum CodingKeys中没有"_transcode""_transcoder" rawValues的要求。

除此之外,您还可以将TopLevelCodingKeys用作keyDecodingStrategy来处理下划线表示法( 蛇格表示法 ),即

.convertFromSnakeCase

因此,您无需显式处理所有蛇形键do { let decoder = JSONDecoder() decoder.keyDecodingStrategy = .convertFromSnakeCase //here..... let model = try decoder.decode(CreatePostResponseModel.self, from: data) print(model) } catch { print(error) } 将自行处理。

答案 1 :(得分:1)

这可能是适合您的好解决方案之一,无论您想在哪里为一个变量添加多个键:

var transcodeId:String?

public init(from decoder: Decoder) throws {

    do {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        transcodeId =  container.getValueFromAvailableKey(codingKeys: [CodingKeys._transcoder,CodingKeys._transcode])
    } catch {
        print("Error reading config file: \(error.localizedDescription)")
    }
}

extension KeyedDecodingContainerProtocol{

    func getValueFromAvailableKey(codingKeys:[CodingKey])-> String?{
         for key in codingKeys{
             for keyPath in self.allKeys{
                 if key.stringValue == keyPath.stringValue{
                    do{ 
                        return try self.decodeIfPresent(String.self, forKey: keyPath)
                    } catch {
                        return nil
                    }
                }
            }
        }
        return nil
    }
}

希望有帮助。

答案 2 :(得分:0)

由编译器生成的init(from:)是全有还是全无。您不能让它解码某些密钥,而不能“手动”解码其他密钥。

使用编译器生成的init(from:)的一种方法是给struct 两者都提供可能的编码属性,并使transcodeId成为计算属性:

struct CreatePostResponseModel: Codable {
    var transcodeId: String? {
        get { _transcode ?? _transcoder }
        set { _transcode = newValue; _transcoder = nil }
    }

    var _transcode: String? = nil
    var _transcoder: String? = nil

    var id: String = “”
    // other properties
}