close
自訂屬性包裝器(property wrapper) ,
找不到key、String, Int, Double, CGFloat 嘗試轉型,都失敗會給預設值。
protocol DefaultValue {
associatedtype Value: Decodable
static var defaultValue: Value { get }
}
extension Int {
struct Zero: DefaultValue {
static var defaultValue: Int { 0 }
}
}
extension Bool {
struct True: DefaultValue {
static var defaultValue: Bool { true }
}
struct False: DefaultValue {
static var defaultValue: Bool { false }
}
}
extension Double {
struct Zero: DefaultValue {
static var defaultValue: Double { 0.0 }
}
}
extension CGFloat {
struct Zero: DefaultValue {
static var defaultValue: Double { 0.0 }
}
}
extension String {
struct Empty: DefaultValue {
static var defaultValue: String { "" }
}
}
extension Array where Element: Decodable {
/// 解失敗給預設值 []
/// ```
/// /// 廣告相關
/// @Default or @Default
/// var ad: [Ad]
/// ```
struct Empty: DefaultValue {
static var defaultValue: Array { [] }
}
}
/// 用在JSON 反序列化 (套在欲decode的屬性上)
/// ```
/// /// 廣告相關
/// @Default<[Ad]> or @Default
/// var ad: [Ad]
/// ```
///
/// ```
/// /// e.g. 326532
/// @Default or @Default.EmptyString
/// var article_id: String
/// ```
/// - 支援 Int, Bool, Double, CGFloat, String, Array
/// - 找不到key,設成預設值
/// - 型態不符(String, Int, Double, CGFloat),會嘗試轉型
@propertyWrapper
struct Default {
var wrappedValue: T.Value
}
/// MARK - 縮短泛型方便使用
extension Default {
typealias True = Default
typealias False = Default
typealias EmptyString = Default
}
extension Default: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
wrappedValue = {
switch T.Value.self {
case is String.Type:
// Int, Double to Stirng
let value: String? = {
if let value = (try? container.decode(String.self)) {
return value
} else if let value = (try? container.decode(Int.self)) {
return String(value)
} else if let value = (try? container.decode(Double.self)) {
return String(value)
} else {
return nil
}
}()
return value as? T.Value ?? T.defaultValue // 轉型失敗有預設值
case is Int.Type:
// Stirng, Double to Int
let value: Int? = {
if let value = (try? container.decode(Int.self)) {
return value
} else if let value = (try? container.decode(String.self)) {
return Int(value)
} else if let value = (try? container.decode(Double.self)) {
return Int(value)
} else {
return nil
}
}()
return value as? T.Value ?? T.defaultValue // 轉型失敗有預設值
case is Double.Type:
// Stirng, Int to Double
let value: Double? = {
if let value = (try? container.decode(Double.self)) {
return value
} else if let value = (try? container.decode(String.self)) {
return Double(value)
} else if let value = (try? container.decode(Int.self)) {
return Double(value)
} else {
return nil
}
}()
return value as? T.Value ?? T.defaultValue // 轉型失敗有預設值
case is CGFloat.Type:
// Stirng, Int to CGFloat
let value: CGFloat? = {
if let value = (try? container.decode(CGFloat.self)) {
return value
} else if let value = (try? container.decode(String.self)) {
return CGFloat(value)
} else if let value = (try? container.decode(Int.self)) {
return CGFloat(value)
} else {
return nil
}
}()
return value as? T.Value ?? T.defaultValue // 轉型失敗有預設值
default:
return (try? container.decode(T.Value.self)) ?? T.defaultValue // decode失敗有預設值
}
}()
}
}
extension KeyedDecodingContainer {
func decode(_ type: Default.Type, forKey key: Key) throws -> Default where T: DefaultValue {
// 沒Key時給預設值
try decodeIfPresent(type, forKey: key) ?? Default(wrappedValue: T.defaultValue)
}
}
全站熱搜