1 关于Optional
使用swift开发项目中会用大所谓的可选类型,如下面的:
var age:Int?
我们做做业务是往往使用 if 或者 guard来走
代码语言:javascript复制
guard let age = age else {
return
}
if let mAge = age {
}
var b = age ?? 0
第三种的解包造成大量的'??', 对于接触一段时间swift就知道上面age的声明内部其实是一个Optional的类型,等价于:
var age:Optional<Int>
基于此我们是不是可以根据局这个思路读Optional机型一次扩展来消灭使用中的??判断
思路大致是:为数据类型设置默认值
代码语言:javascript复制
public protocol Letable {
static func defaultLetValue() -> Self
}
// 其他类型可以模仿此
extension String : Letable {
public static func defaultLetValue() -> String {
return ""
}
}
这样我们就可以对Optionalzuo 泛型约束进行扩展
代码语言:javascript复制public
extension Optional where Wrapped : Letable {
var `let`:Wrapped {
switch self {
case .none:
return Wrapped.defaultLetValue()
case .some(let value):
return value
}
}
}
public extension Optional {
@inlinable
func `let`(_ block: (Wrapped)->Void) {
switch self {
case .none:
break
case .some(let value):
block(value)
}
}
}
我们看看怎么使用:
代码语言:javascript复制
var c:Bool? // c.let
let a:String? // a.let
let aa:String?
aa.let { (v) in
XCTAssert(false, "此时不会执行的")
}
var stu: Studnt?
stu.let { (v) in
XCTAssertTrue(v is Studnt)
}
2 关于链式
链式这个也是基于协议的扩展与泛型约束来使用,进行一些数据的扩展
代码语言:javascript复制
public
protocol Thenable {}
public
extension Thenable where Self : Any {
func with(_ block: (inout Self)throws -> Void) rethrows -> Self {
var copy = self
try block(©)
return copy
}
func `do`(_ block: (Self)throws -> Void) rethrows {
try block(self)
}
}
public
extension Thenable where Self: AnyObject {
func then(_ block:(Self) throws -> Void) rethrows -> Self {
try block(self)
return self
}
}
extension Array: Thenable {}
extension Dictionary: Thenable {}
extension Set: Thenable {}
extension NSObject: Thenable {}
#if os(iOS) || os(tvOS)
extension UIEdgeInsets : Thenable {}
extension UIOffset : Thenable {}
extension UIRectEdge: Thenable{}
#endif
#if !os(Linux)
extension CGPoint: Thenable {}
extension CGRect: Thenable {}
extension CGSize: Thenable {}
extension CGVector: Thenable {}
#endif
整体的代码量不多,但是很具有f鞥个
代码语言:javascript复制let label = UILabel().then {
$0.textColor = .red
$0.textAlignment = .center
}
代码语言:javascript复制 UserDefaults.standard.do {
$0.set("aa", forKey: "aKey")
$0.synchronize()
}
代码语言:javascript复制let rect = CGRect(x: 0, y: 0, width: 0, height: 0).with {
$0.origin.x = 100
$0.size.width = 100
}
3 属性包装器在Codable中的使用
属性包装器着实有点不同,具体使用大家百度科普,这里我们将其搬运到我们Codable中缩减避免我们Json数据解析问题。
COdable中不完美的一点是非Optional对应数据缺失往往会解析失败
对于这个问题我们可以仿照上文1 的方式设置类型默认值,外加属性包装器来解决
代码语言:javascript复制public protocol DefaultValue {
associatedtype Value: Codable
static var defaultValue: Value { get }
}
@propertyWrapper
struct Default<T: DefaultValue> where T == T.Value {
var wrappedValue: T.Value
var value:T.Value?
init(_ value: T.Value? = nil) {
self.value = value
if let value = value {
wrappedValue = value
} else {
wrappedValue = T.defaultValue
}
}
}
我们首先定义可以修饰能被Codable的泛型属性包装器
代码语言:javascript复制extension Default : Encodable {
func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try container.encode(wrappedValue)
}
}
extension Default: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
wrappedValue = (try? container.decode(T.Value.self)) ?? T.defaultValue
}
}
extension KeyedDecodingContainer {
func decode<T>(
_ type: Default<T>.Type,
forKey key: Key
) throws -> Default<T> where T: DefaultValue {
let value = (try decodeIfPresent(type, forKey: key))
return value ?? Default(T.defaultValue)
}
}
之后我们自定义属性包装器自身的Codable
到此是我们的属性包装器自身可Codable,同时又可修饰Codable,还能在key值缺失是使用泛型的默认值作为数据,一切看似都很完美了
到此我们即可实现大部分功能了
代码语言:javascript复制struct Video: Codable {
@Default var id: Int
@Default(22) var age: Int
@Default var title: String
@Default(true) var commentEnabled: Bool
}
但是我们还缺少一样实例Array,老规矩使用泛型约束来吧
代码语言:javascript复制
extension Array :DefaultValue where Element:DefaultValue , Element: Codable {
public typealias Value = Array<Element>
public static var defaultValue: Array<Element> {
return []
}
}
至此你可以这么使用了
代码语言:javascript复制 @Default var list:[Person]
也学到此刻你觉得已经完美了,其实还有一个问题我们怎么处理Optional呢?---答案是扩展遵循协议啦
代码语言:javascript复制
extension Optional : DefaultValue where Wrapped: Codable, Wrapped:DefaultValue {
public typealias Value = Optional<Wrapped>
public static var defaultValue: Optional<Wrapped> {
return Optional.init(Wrapped.defaultValue as! Wrapped)
}
}
至此基本的jiu完成啦