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

propertye wrapped, optional在Swift妙用

作者头像
大话swift
发布于 2021-03-18 03:29:06
发布于 2021-03-18 03:29:06
1.1K11
代码可运行
举报
文章被收录于专栏:大话swift大话swift
运行总次数:1
代码可运行

1 关于Optional

使用swift开发项目中会用大所谓的可选类型,如下面的:

var age:Int?

我们做做业务是往往使用 if 或者 guard来走

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

guard let age = age else {
    return
}

if let mAge = age  {
    
}

var b = age ?? 0

第三种的解包造成大量的'??', 对于接触一段时间swift就知道上面age的声明内部其实是一个Optional的类型,等价于:

var age:Optional<Int>

基于此我们是不是可以根据局这个思路读Optional机型一次扩展来消灭使用中的??判断

思路大致是:为数据类型设置默认值

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

public protocol Letable  {
    static func defaultLetValue() -> Self
}

// 其他类型可以模仿此
extension String : Letable {
    public static func defaultLetValue() -> String {
        return ""
    }
}

这样我们就可以对Optionalzuo 泛型约束进行扩展

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制

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
代码运行次数:0
运行
AI代码解释
复制


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
代码运行次数:0
运行
AI代码解释
复制
let label =  UILabel().then {
            $0.textColor = .red
            $0.textAlignment = .center
        }
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 UserDefaults.standard.do {
            $0.set("aa", forKey: "aKey")
            $0.synchronize()
        }
 
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
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
代码运行次数:0
运行
AI代码解释
复制
struct Video: Codable {
    
    @Default var id: Int
    
    @Default(22) var age: Int
    
    @Default var title: String
    
    @Default(true) var commentEnabled: Bool
    
    }

但是我们还缺少一样实例Array,老规矩使用泛型约束来吧

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

extension Array :DefaultValue where Element:DefaultValue , Element: Codable {
    public typealias Value = Array<Element>
    public static var defaultValue: Array<Element> {
        return []
    }
}

至此你可以这么使用了

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    @Default var list:[Person]

也学到此刻你觉得已经完美了,其实还有一个问题我们怎么处理Optional呢?---答案是扩展遵循协议啦

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

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 删除。

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

评论
登录后参与评论
1 条评论
热度
最新
@Default var id: IntProperty type 'Int' does not match that of the 'wrappedValue' property of its wrapper type 'Default’;@Default(22) var age: IntGeneric struct 'Default' requires that 'Int' conform to 'DefaultValue’;@Default var title: StringProperty type 'String' does not match that of the
@Default var id: IntProperty type 'Int' does not match that of the 'wrappedValue' property of its wrapper type 'Default’;@Default(22) var age: IntGeneric struct 'Default' requires that 'Int' conform to 'DefaultValue’;@Default var title: StringProperty type 'String' does not match that of the
回复回复点赞举报
推荐阅读
编辑精选文章
换一批
46 道 Swift 常见面试题解
3、Set 独有的方法有哪些? 4、实现一个 min 函数,返回两个元素较小的元素 5、map、filter、reduce 的作用 6、map 与 flatmap 的区别 7、什么是 copy on write 8、如何获取当前代码的函数名和行号 9、如何声明一个只能被类 conform 的 protocol 10、guard 使用场景 11、defer 使用场景 12、String 与 NSString 的关系与区别 13、怎么获取一个 String 的长度 14、如何截取 String 的某段字符串 15、throws 和 rethrows 的用法与作用 16、try?和 try!是什么意思 17、associatedtype 的作用 18、什么时候使用 final 19、public 和 open 的区别 20、声明一个只有一个参数没有返回值闭包的别名
Swift社区
2021/11/26
5.7K0
谈谈 Swift 中 Sequence(序列) 、Collection(集合) 和高阶函数
序列和集合是一门语言中重要的组成部分,下面我们就通过这篇文章来看看 Swift 中的序列和集合。
Swift社区
2021/11/26
2.3K0
谈谈 Swift 中 Sequence(序列) 、Collection(集合) 和高阶函数
Codable 解析 JSON 配置默认值
2017年推出的 Codable 无疑是 Swift 的一大飞跃。尽管当时社区已经构建了多种用于本地 Swift 值和 JSON 之间 的编解码工具,但由于 Codable 与 Swift 编译器本身的集成,提供了前所未有的便利性,使我们能够通过使可解码类型遵守 Decodable 协议来定义可解码类型,例如:
韦弦zhy
2021/04/07
2K0
Swift 5.5 新特性
SE-0296提案终于为开发者带来了期待已久的 async/await,语法基本上和javascript中的很像。
小刀c
2022/08/16
2.7K0
Swift 5.5 新特性
Swift Codable 记录解析路径
在我们的工作中,各种特殊情况都有可能遇到,某些特定情况下,需要我们记录模型的解析路径,例如:
韦弦zhy
2021/11/24
8980
Swift 项目中涉及到 JSONDecoder,网络请求,泛型协议式编程的一些记录和想法
最近项目开发一直在使用 swift,因为 HTN 项目最近会有另外一位同事加入,所以打算对最近涉及到的一些技术和自己的一些想法做个记录,同时也能够方便同事熟悉代码。
用户7451029
2020/06/16
7.1K0
Swift 3到5.1新特性整理
Swift 5.0 最重要的自然是ABI Stability, 对此可以看这篇 Swift ABI 稳定对我们到底意味着什么 。
小刀c
2022/08/16
4.9K0
Swift 3到5.1新特性整理
Swift 5.6到5.10新特性整理
当你编写涉及共享状态的代码时,如果你不确保这个共享状态在跨线程使用时是安全的,你就会在许多地方遇到数据竞争的问题。
小刀c
2024/04/03
2.5K0
Swift 5.6到5.10新特性整理
Swift 5.5 新特性
Swift 5.5 内置于 Xcode 13,虽然版本号只增加了 0.1,看似是一个小版本升级,但却带来了非常多的新内容,其中最大的更新是引入了全新的并发编程方式。
YungFan
2021/07/16
2.2K0
架构之路 (六) —— VIPER架构模式(二)
源码 1. Swift 首先看下工程组织结构 下面就是源码了 1. SceneDelegate.swift import SwiftUI class SceneDelegate: UIRespond
conanma
2021/09/04
1.3K0
Swift基础语法(四)
在Swift5之前,我们一般是采用上面的方式来处理异常,在Swift5之后,苹果推出了一个Result枚举,Result枚举可以更加优雅地去处理异常。
拉维
2020/07/06
4.3K0
Swift基础语法(四)
用Swift写一个响应式编程库
本文介绍了如何使用 Reactive Programming 的方式在 Swift 中实现信号量,通过使用 Signal 和 Disposable 两个概念来模拟实现信号量,以解决在多线程环境下对共享资源的访问控制问题。同时,也介绍了一种使用 Combine 框架来实现线程安全的信号量,以及如何使用 Combine 来实现一个类似于 RxSwift 的响应式编程库。
企鹅号小编
2018/01/03
1.1K0
Swift系列八 - 闭包
要想使用exec函数,则必须传入两个Int类型的参数和一个返回Int类型的函数,然后exec内部执行了传入的函数。
呆呆
2021/05/27
4610
Swift 5.6 新特性
Swift 5.6 之前只有#available表示可用,Swift 5.6 之后增加了#unavailable表示不可用,二者意思相反。
YungFan
2022/03/30
1.3K0
Swift 5.2到5.4新特性整理
SE-0287提案改进了Swift使用隐式成员表达式的能力。Swift 5.4之后不但可以使用单个 使用,而且可以链起来使用。
小刀c
2022/08/16
2.3K0
Swift 5.2到5.4新特性整理
UserDefaults 浅析及其使用管理
我想每一个 iOSer 对UserDefaults都有所了解,但大家真的完全了解它吗?下面,我谈谈我对UserDefaults的看法。
CoderStar
2022/08/24
1.3K0
@AppStorage研究
在苹果生态的应用中,开发者或多或少都会使用到UserDefaults。我个人习惯将可被用户自定义的配置信息(精度、单位、色彩等)保存在UserDefaults中。随着配置信息的增加,在SwiftUI视图中使用的@AppStorage越来越多。
东坡肘子
2022/07/28
1.6K0
Codable发布这么久我就不学,摸鱼爽歪歪,哎~就是玩儿
对于大多数的应用程序来说,最常见的任务就是进行网络数据的发送和接收,但是在执行此操作之前,我们需要通过编码或者序列化的方式将数据转换为合适的格式来发送,然后还需要将收到的网络数据转换为合适的格式,这样才能在应用中使用它们,这样的过程叫做解码或着叫反序列化。
HelloWorld杰少
2022/08/04
2K0
Swift 进阶: 泛型
泛型代码让你能根据你所定义的要求写出可以用于任何类型的灵活的、可复用的函数。你可以编写出可复用、意图表达清晰、抽象的代码。
Swift社区
2021/11/26
1.9K0
Swift 进阶: 泛型
Swift进阶二:基本数据类型相关
而在Objective-C中,如果没有特殊的指明,我们所声明的都是变量。可以通过如下几种方式来声明常量:
拉维
2020/07/20
9240
Swift进阶二:基本数据类型相关
相关推荐
46 道 Swift 常见面试题解
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档