美文网首页
Swift 属性包装器:让不可变属性拥有一个默认值

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

作者: 芮淼一线 | 来源:发表于2022-09-07 21:32 被阅读0次

说明

属性包装器:让不可选变量拥有一个默认值,以解决使用使用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<Source: JSONWrapperSource> {
        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<T>(_ type: JSONWrapper.Wrapper<T>.Type,
                   forKey key: Key) throws -> JSONWrapper.Wrapper<T> {
        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<T: List>: Source {
            static var defaultValue: T { [] }
        }

        enum EmptyMap<T: Map>: 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<T: List> = Wrapper<Sources.EmptyList<T>>
    typealias JSONMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
    typealias JSONTrue = Wrapper<Sources.True>
    typealias JSONFalse = Wrapper<Sources.False>
    typealias JSONString = Wrapper<Sources.DefaultString>
    typealias JSONInt = Wrapper<Sources.DefaultInt>
    typealias JSONFloat = Wrapper<Sources.DefaultFloat>
}






// 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 属性包装器:让不可变属性拥有一个默认值

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