Swift 属性包装器:让不可变属性拥有一个默认值

说明

属性包装器:让不可选变量拥有一个默认值,以解决使用使用Codable解析JSON时出现nil值解析失败的问题。

代码


//
//  JSONWrapper.swift
//  Tsss
//
//  Created by PC on 2022/9/8.
//

import Foundation


/**
 属性包装器:让不可选变量拥有一个默认值,以解决使用使用Codable解析JSON时出现nil值解析失败的问题。

 翻译:https://www.jianshu.com/p/47ad03117e59
 原文:https://www.swiftbysundell.com/tips/default-decoding-values/
 */


protocol JSONWrapperSource {
    associatedtype Value: Decodable
    static var defaultValue: Value { get }
}

enum JSONWrapper {

}

extension JSONWrapper {
    @propertyWrapper
    struct Wrapper {
        typealias Value = Source.Value
        var wrappedValue = Source.defaultValue
    }
}

extension JSONWrapper.Wrapper: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        wrappedValue = try container.decode(Value.self)
    }
}

/**
 通过扩展KeyedDecodingContainer来重载解码特定的类型来完成,在这种情况下,我们仅在存在值的情况下继续解码给定的键,否则我们将返回包装器的空实例
 */
extension KeyedDecodingContainer {
    func decode(_ type: JSONWrapper.Wrapper.Type,
                   forKey key: Key) throws -> JSONWrapper.Wrapper {
        try decodeIfPresent(type, forKey: key) ?? .init()
    }
}

extension JSONWrapper.Wrapper: Equatable where Value: Equatable {}
extension JSONWrapper.Wrapper: Hashable where Value: Hashable {}
extension JSONWrapper.Wrapper: Encodable where Value: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(wrappedValue)
    }
}

// MARK: - 配置各种类型的默认值
extension JSONWrapper {
    typealias Source = JSONWrapperSource
    typealias List = Decodable & ExpressibleByArrayLiteral
    typealias Map = Decodable & ExpressibleByDictionaryLiteral

    enum Sources {

        enum EmptyList: Source {
            static var defaultValue: T { [] }
        }

        enum EmptyMap: Source {
            static var defaultValue: T { [:] }
        }

        enum DefaultString: Source {
            static var defaultValue: String { "" }
        }

        enum True: Source {
            static var defaultValue: Bool { true }
        }

        enum False: Source {
            static var defaultValue: Bool { false }
        }

        enum DefaultInt:Source {
            static var defaultValue: Int { 0 }
        }

        enum DefaultFloat:Source {
            static var defaultValue: Float { 0.0 }
        }

        //可追加更多的自定义类型默认值
    }
    
}

// MARK: - 包装器属性别名
extension JSONWrapper {
    typealias JSONList = Wrapper>
    typealias JSONMap = Wrapper>
    typealias JSONTrue = Wrapper
    typealias JSONFalse = Wrapper
    typealias JSONString = Wrapper
    typealias JSONInt = Wrapper
    typealias JSONFloat = Wrapper
}






// MARK: - 使用示例
/*
struct Test:Codable{
    @JSONWrapper.JSONString var a:String
    @JSONWrapper.JSONFalse var b:Bool
    @JSONWrapper.JSONInt var c:Int
}

对象创建:
Codable: 使用方式不变,直接JSONEncoder,JSONDecoder操作即可
手动创建: let obj = Test(a:.init(wrappedValue: "test-string")) , 即需要使用属性包装器的init(wrappedValue:)方式创建
**/



引用

翻译:https://www.jianshu.com/p/47ad03117e59
原文:https://www.swiftbysundell.com/tips/default-decoding-values/

你可能感兴趣的:(Swift 属性包装器:让不可变属性拥有一个默认值)