Swift:优雅又强大的语法糖——Then库

懒加载组件书写的困恼

我写UI组件,特别喜欢使用全局下面的懒加载,大概形式如下:

swift 复制代码
class ViewController: UIViewController {
    
    private lazy var label: UILabel = {
        let label = UILabel()
        label.text = "season"
        return label
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        view.addSubview(label)
    }
}

我这么写有几个原因:

  • 组件只有在确实被调用的时候才会被调用了;
  • 将其设为全局,如果后续需要对赋值或者更新,信手捏来

但是!但是这么写非常的繁琐:

我需要声明类型: UILabel,同时在大括号里面初始化一个label并且return label!想想我都觉得自己不停的废话,如果一页有非常多UI组件,实在很遭罪!

有人会说,你可以用AI呀,GitHub Copilot for Xcode,虽然它会联系上下文,可以让我一路tab,但是这玩意有延迟,同时它也是收费的,白嫖完次数就没补全了。

直到我使用了Then,瞬间被其语法糖折服,这是使用Then库之后的代码:

swift 复制代码
class ViewController: UIViewController {
    
    private lazy var label = UILabel().then { $0.text = "season" }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .white
        
        view.addSubview(label)
    }
}

Then 是一个非常简洁实用的 Swift 框架,主要用于让对象的初始化和属性配置更加优雅和简洁。它通过扩展 Swift 的类型,提供了链式语法,让你可以在创建对象时直接配置属性,提升代码可读性和开发效率。

1. 基本用法

示例:

swift 复制代码
import Then

let label = UILabel().then {
    $0.text = "Hello, Then!"
    $0.textColor = .red
    $0.textAlignment = .center
}

private lazy var button = UIButton(type: .custom).then {
    $0.setTitle("你打我撒~", for: .normal)
    $0.setTitleColor(.systemBlue, for: .normal)
    $0.setImage(UIImage(named: "小剑剑"), for: .normal)
}

这样你就可以在初始化对象的同时,直接配置它的属性,避免多次写变量名。

2. 支持的类型

Then 支持所有继承自 NSObject 的类(如 UIKit 组件),以及结构体(如 CGRect、CGSize、UIEdgeInsets 等)。

结构体用法:

swift 复制代码
let rect = CGRect().with {
    $0.origin.x = 10
    $0.size.width = 100
}

3. 源码解析

Then 的核心实现其实非常简单,主要是通过 Swift 的协议扩展:

swift 复制代码
public protocol Then {}

extension Then {

    @inlinable public func with(_ block: (inout Self) throws -> Void) rethrows -> Self

    @inlinable public func `do`(_ block: (Self) throws -> Void) rethrows
}

extension Then where Self : AnyObject {
    @inlinable public func then(_ block: (Self) throws -> Void) rethrows -> Self
}

extension NSObject: Then {}

#if !os(Linux)
  extension CGPoint: Then {}
  extension CGRect: Then {}
  extension CGSize: Then {}
  extension CGVector: Then {}
#endif

extension Array: Then {}
extension Dictionary: Then {}
extension Set: Then {}
extension JSONDecoder: Then {}
extension JSONEncoder: Then {}

#if os(iOS) || os(tvOS)
  extension UIEdgeInsets: Then {}
  extension UIOffset: Then {}
  extension UIRectEdge: Then {}
#endif
  • 只要你的类型是 NSObject 的子类,就自动拥有了 then 方法。
  • 结构体则通过 with 实现类似功能。
  • do即可以在类里面使用,也可以在结构体中使用。
  • 库对Swift内置的一些结构体类型做了扩展,以方便使用。

这里把@inlinable单独拿出来说一下,我以前也见的多,也知道和性能有关系,不过确实是那么了解。

@inlinable的作用

@inlinable 是 Swift 的一个函数属性修饰符,主要作用如下:

作用

  • 允许函数体在模块外可见
    @inlinable 修饰的方法或属性,其实现代码会暴露给其他模块(即使是 internal 访问级别),这样编译器可以在调用处直接内联优化,提高性能。
  • 提升性能
    编译器可以将这些方法的调用"内联",减少函数调用开销,尤其适用于小型、频繁调用的函数。

典型使用场景

  • 框架或库中希望对外暴露实现细节、让调用方获得更好性能的公共 API。
  • 例如 Swift 标准库中很多常用方法都用 @inlinable 修饰。

注意事项

  • 滥用可能导致编译体积变大,因为实现代码会被复制到每个调用点。
  • 只建议用于小型、性能敏感的函数。

小结:

@inlinable 让方法实现对外可见,便于跨模块内联优化,常用于 Swift 框架和库的高性能 API。

4.thenwithdo 的用法解析

①. then

swift 复制代码
let label = UILabel().then {
    $0.text = "Hello"
    $0.textColor = .red
}

②. with

  • 适用对象 :结构体(struct),如 CGRectCGSize 等。
  • 作用:复制结构体,配置属性后返回新的结构体实例(因为结构体是值类型,不能直接修改原对象)。
  • 常见用法
swift 复制代码
let rect = CGRect().with {
    $0.origin.x = 10
    $0.size.width = 100
}
// rect 是配置后的新实例

③. do

  • 适用对象:类和结构体都可以。
  • 作用 :对对象执行一些操作,但不返回对象本身,通常用于执行副作用(如调用方法、打印等)。
  • 常见用法
swift 复制代码
UserDefaults.standard.do {
    $0.set("value", forKey: "key")
    $0.synchronize()
}
// 仅执行 block 内操作,不返回对象

总结对比

方法 适用类型 是否返回对象 主要用途
then 初始化并配置属性
with 结构体 配置属性并返回新实例
do 类/结构体 执行副作用操作

一句话记忆:

  • then 用于类的链式属性配置,
  • with 用于结构体的链式属性配置,
  • do 用于执行操作但不返回对象。

5. 优势总结

  • 链式语法,代码更简洁
  • 初始化和配置合二为一
  • 适用于类和结构体
  • 虽然对业务代码无侵入性,易于集成,但是,一旦使用了Then,代码里面都使用了这种书写格式,想要去掉Then库就特别困难了

6. 典型场景

  • UI 组件的属性配置
  • Model 对象的初始化
  • 结构体的便捷赋值

结论:

Then 是一个轻量级、无侵入的 Swift 语法糖工具,极大提升了代码的可读性和开发效率,推荐在日常开发中使用。

同时Then更难得可贵的是其面向协议编程的思想,通过协议下扩展的方法,最后让需要使用的类型去遵守协议,以达到四两拨千斤的目的。

Swift面向协议的思想,在很多场景下都有非常不错的效果,值得我们反复揣摩与学习。

我最早接触then这个关键词是在JavaScript中的网络请求中的异步回调中,then里面是网络请求的响应,虽然Swift中并不完全是这个意思,不过还是非常便于理解的。

相关推荐
WindrunnerMax2 小时前
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
前端·架构·github
Digitally2 小时前
如何在没有 iTunes 的情况下备份 iPhone
ios·iphone
HarderCoder2 小时前
ByAI:iOS 生命周期:AppDelegate 与 SceneDelegate 中的 `willEnterForeground` 方法解析
swift
hstar95272 小时前
三十五、面向对象底层逻辑-Spring MVC中AbstractXlsxStreamingView的设计
java·后端·spring·设计模式·架构·mvc
大模型之路2 小时前
基于本地LLM与MCP架构构建AI智能体全指南
人工智能·架构
大熊猫侯佩2 小时前
SwiftData 如何在 Widgets 和 App 的界面之间同步数据变化?
swiftui·swift·apple watch
香蕉可乐荷包蛋2 小时前
前端现行架构浅析
前端·架构
宇努力学习2 小时前
浅谈未来汽车电子电气架构发展趋势中的通信部分
架构·can·以太网·汽车电子
YungFan2 小时前
SwiftUI-Preference
swiftui·swift