美文网首页
Swift Codeable协议

Swift Codeable协议

作者: 睡不醒小迷妹 | 来源:发表于2020-07-18 10:31 被阅读0次

    前言

    Swift 4.0版本引入了一种新的对象序列化的方式Codeable,用于代替原先OC语法的NSCode协议。
    在程序执行过程中,我们经常需要通过网络发送数据,保存数据到磁盘,这往往是一个对象序列化的过程;在Swift4.0开始,系统提供一套对象编解码的协议,可以自动或者自定义的实现对象的序列化。

    typealias Codable = Decodable & Encodable
    

    自动解码和编码

    想要对象可编码,最简单的方式就是用可编码的类型去声明属性;

    为了描述简单,结构体和对象都描述为对象

    这些可编码的属性包括:Int String Double Date Data URL

    struct Landmark {
        var name: String
        var foundingYear: Int
    }
    

    接下来,我们只需要让对象实现Codeable协议,该对象就自动实现了编码和解码。

    struct Landmark: Codable {
        var name: String
        var foundingYear: Int
        
        // Landmark now supports the Codable methods init(from:) and encode(to:), 
        // even though they aren't written as part of its declaration.
    }
    

    但是我们平常开发中,属性往往也是自定义对象,在Codeable协议中,只需要所有的属性都支持编解码,那么该对象也能编解码。

    struct Coordinate: Codable {
        var latitude: Double
        var longitude: Double
    }
    
    struct Landmark: Codable {
        // Double, String, and Int all conform to Codable.
        var name: String
        var foundingYear: Int
        
        // Adding a property of a custom Codable type maintains overall Codable conformance.
        var location: Coordinate
    }
    

    内置的类型,比如Array Dictionary,只需要元素实现了Codeable,那么也支持编解码。

    struct Landmark: Codable {
        var name: String
        var foundingYear: Int
        var location: Coordinate
        
        // Landmark is still codable after adding these properties.
        var vantagePoints: [Coordinate]
        var metadata: [String: String]
        var website: URL?
    }
    

    手动解码和编码

    如果你对象和编码结构不同,你可以自定义编码和解码协议的实现,完成对象的编码和解码。

    struct Coordinate {
        var latitude: Double
        var longitude: Double
        var elevation: Double
    
        enum CodingKeys: String, CodingKey {
            case latitude
            case longitude
            case additionalInfo
        }
        
        enum AdditionalInfoKeys: String, CodingKey {
            case elevation
        }
    }
    

    解码实现init(from decoder: Decoder)

    extension Coordinate: Decodable {
        init(from decoder: Decoder) throws {
            let values = try decoder.container(keyedBy: CodingKeys.self)
            latitude = try values.decode(Double.self, forKey: .latitude)
            longitude = try values.decode(Double.self, forKey: .longitude)
            
            let additionalInfo = try values.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
            elevation = try additionalInfo.decode(Double.self, forKey: .elevation)
        }
    }
    

    编码实现 encode(to encoder: Encoder)

    extension Coordinate: Encodable {
        func encode(to encoder: Encoder) throws {
            var container = encoder.container(keyedBy: CodingKeys.self)
            try container.encode(latitude, forKey: .latitude)
            try container.encode(longitude, forKey: .longitude)
            
            var additionalInfo = container.nestedContainer(keyedBy: AdditionalInfoKeys.self, forKey: .additionalInfo)
            try additionalInfo.encode(elevation, forKey: .elevation)
        }
    }
    

    JSONEncoder & JSONDecoder

    Swift提供了系统的JSON数据的编解码方式,可以将实现Codeable对象和JSON对象相互转化,非常的简单和方便。

    struct GroceryProduct: Codable {
        var name: String
        var points: Int
        var description: String?
    }
    
    let pear = GroceryProduct(name: "Pear", points: 250, description: "A ripe pear.")
    
    let encoder = JSONEncoder()
    encoder.outputFormatting = .prettyPrinted
    
    let data = try encoder.encode(pear)
    print(String(data: data, encoding: .utf8)!)
    
    /* Prints:
     {
       "name" : "Pear",
       "points" : 250,
       "description" : "A ripe pear."
     }
    */
    
    struct GroceryProduct: Codable {
        var name: String
        var points: Int
        var description: String?
    }
    
    let json = """
    {
        "name": "Durian",
        "points": 600,
        "description": "A fruit with a distinctive scent."
    }
    """.data(using: .utf8)!
    
    let decoder = JSONDecoder()
    let product = try decoder.decode(GroceryProduct.self, from: json)
    
    print(product.name) // Prints "Durian"
    

    PS

    我自己写的一个KV存储库SwiftLvDB,也将支持Codeable对象存储,敬请关注。

    参考

    https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
    https://developer.apple.com/documentation/foundation/jsonencoder
    https://developer.apple.com/documentation/foundation/jsondecoder

    相关文章

      网友评论

          本文标题:Swift Codeable协议

          本文链接:https://www.haomeiwen.com/subject/buexkktx.html