前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >propertye wrapped, optional在Swift妙用

propertye wrapped, optional在Swift妙用

作者头像
大话swift
发布2021-03-18 11:29:06
1K1
发布2021-03-18 11:29:06
举报
文章被收录于专栏:大话swift

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(&copy)
        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完成啦

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-03-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大话swift 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档