Observable - 可被监听的序列
所有的事物都是序列Observable 可以用于描述元素异步产生的序列。这样我们生活中许多事物都可以通过它来表示。
如何创建序列创建序列最直接的方法就是调用 Observable.create,然后在构建函数里面描述元素的产生过程。 observer.onNext(0) 就代表产生了一个元素,他的值是 0。后面又产生了 9 个元素分别是 1, 2, ... 8, 9 。最后,用 observer.onCompleted() 表示元素已经全部产生,没有更多元素了。
你可以用这种方式来封装功能组件,例如,闭包回调:
12345678910111213141516171819202122232425typealias JSON = Anylet json: Observable<JSON> = Observable.create { (observer) -> Disposable in let task = URLSession.shared.dataTask(with: ...) { dat ...
响应式框架
未读函数响应式编程
函数响应式编程是种编程范式。它是通过构建函数操作数据序列,然后对这些序列做出响应的编程方式。它结合了函数式编程以及响应式编程。
函数式编程函数式编程是种编程范式,它需要我们将函数作为参数传递,或者作为返回值返还。我们可以通过组合不同的函数来得到想要的结果。
函数试编程的优点:
灵活
高复用
简洁
易维护
适应各种需求变化
函数式编程 -> 函数响应式编程1234567// 假设用户在进入页面到离开页面期间,总共点击按钮 3 次// 按钮点击序列let taps: Array<Void> = [(), (), ()]// 每次点击后弹出提示框taps.forEach { showAlert() }
这样处理点击事件是非常理想的,但是问题是这个序列里面的元素(点击事件)是异步产生的,传统序列是无法描叙这种元素异步产生的情况。为了解决这个问题,于是就产生了可被监听的序列 Observable<Element> 。它也是一个序列,只不过这个序列里面的元素可以是同步产生的,也可以是异步产生的:
12345// 按钮点击序 ...
Schedulers - 调度器
Schedulers 是 Rx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行。
如果你曾经使用过 GCD, 那你对以下代码应该不会陌生:
1234567// 后台取得数据,主线程处理结果DispatchQueue.global(qos: .userInitiated).async { let data = try? Data(contentsOf: url) DispatchQueue.main.async { self.data = data }}
如果用 RxSwift 来实现,大致是这样的:
123456789let rxData: Observable<Data> = ... rxData .subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated)) .observeOn(MainScheduler.instance) .subscribe(o ...
编程语言
未读Swift 的协议和 Objective-C 的协议不同。Swift 协议可以被用作代理,也可以让你对接口进行抽象 (比如 IteratorProtocol 和 Sequence )。它们和 Objective-C 协议的最大不同在于我们可以让结构体和枚举类型满足协议。除此之外,Swift 协议还可以有关联类型。我们还可以通过协议扩展的方式为协议添加方法实现。我们会在面向协议编程的部分讨论所有这些内容。
协议允许我们进行动态派发,也就是说,在运行时程序会根据消息接收者的类型去选择正确的方法实现。
在面向对象编程中,子类是在多个类之间共享代码的有效方式。不过在 Swift 中,Sequence 中的代码共享是通过协议和协议扩展来实现的。通过这么做,Sequence 协议和它的扩展在结构体和枚举这样的值类型中依然可用,而这些值类型是不支持子类继承的。
协议扩展是一种可以在不共享基类的前提下共享代码的方法。协议定义了一组最小可行的方法集合,以供类型进行实现。而类型通过扩展的方式在这些最小方法上实现更多更复杂的特性。
面向协议编程
比如在一个图形应用中,我们想要进行两种渲染:我们会将图形使 ...
实现效果
控件 — UICollectionView
这个动画是用 UICollectionView 实现的,简单讲下 UICollectionView 的工作原理。这里用到的 UICollectionView 也就3部分:ViewController(简称VC)、UICollectionViewCell、UICollectionViewLayout。
ViewController :在VC里,UICollectionView 的用法跟 UITableView 的用法类似。这里的初始化方法与 UITableview 有所不同,多了个 collectionViewLayout 属性,每个 collectionView 都会绑定一个 UICollectionViewLayout 对象, collectionView 根据这个 layout 对象来布局 cell 。
UICollectionViewCell :这里用的 Cell 实现起来和 UITableViewCell 没什么大区别,我们只要实现它的 initwithFrame 的初始化方法即可,然后实现你想要的布局。
U ...
编程语言
未读和大多数先进语言一样,Swift 拥有不少能被归类于泛型编程下的特性。使用泛型代码,你可以写出可重用的函数和数据结构,只要它们满足你所定义的约束,它们就能够适用于各种类型。比如,像是 Array 和 Set 等多个类型,实际上是它们中的元素类型就是泛型抽象。我们也可以创建泛型方法,它们可以对输入或者输出的类型进行泛型处理。func identity<A>(input: A) -> A 就定义了一个可以作用于任意类型 A 的函数。某种意义上,我们甚至可以认为带有关联类型的协议是“泛型协议”。关联类型允许我们对特定的实现进行抽象。IteratorProtocol 协议就是一个这样的例子:它所生成的 Element 就是一个泛型。
泛型编程的目的是表达算法或者数据结构所要求的核心接口。比如,考虑内建集合一章中的 last(where:) 函数。将它写为 Array 的一个扩展原本是最明显的选择,但是 Array 其实包含了很多 last(where:) 并不需要的特性。通过确认核心接口到底是什么,也就是说,找到想要实现的功能的最小需求,我们可以将这个函数定义在宽阔得多的类型 ...
Swift 支持重载操作符的特性,让我们可以自定义一些简单的计算。最经典的例子就是两个二维向量之间的计算了。
首先我们定义一个二维向量,并创建两个向量
123456struct Vector2D { var x = 0.0 var y = 0.0}let v1 = Vector2D(x: 2.0, y: 3.0)let v2 = Vector2D(x: 1.0, y: 4.0)
相加两个向量:
1let v3 = Vector2D(x: v1.x + v2.x, y: v1.y + v2.y)
这样一次的话,感觉还好。但是遇到复杂的运算的话,这样写感觉就太啰嗦了,这时候重载操作符是最好的选择。
123func +(left: Vector2D, right: Vector2D) -> Vector2D { return Vector2D(x: left.x + right.x, y: left.y + right.y)}
这样,我们相加两个向量就简单的多了
12let v3 = v1 + v2print( ...
编程语言
未读字符串索引
大部分编程语言使用整数值对字符串进行下标操作,比如 str[5] 将会返回 str 中的第六个“字符” (这里的“字符”的概念由所操作的编程语言进行定义)。Swift 不允许这么做。为什么?答案可能现在你已经很耳熟了:因为整数的下标访问无法在常数时间内完成 (对于 Collection 协议来说这也是个直观要求),而且查找第 n 个 Character 的操作也必须要对它之前的所有字节进行检查。
String.Index 是 String 和它的视图所使用的索引类型,它本质上是一个存储了从字符串开头的字节偏移量的不透明值。如果你想计算第 n 个字符所对应的索引,你依然从字符串的开头或结尾开始,并花费 O(n) 的时间。但是一旦你拥有了有效的索引,就可以通过索引下标以 O(1) 的时间对字符串进行访问了。至关重要的是,通过一个已有索引来寻找下一个索引也是很快的,因为你可以从这个已有索引的字节偏移量开始进行查找,而不需要从头开始。正是由于这个原因,按顺序 (前向或者后向) 对字符串中的字符进行迭代是一个高效操作。
对字符串索引的操作的 API 与你在遇到其他任何集合时使用的 ...
Authors: Michael Ilseman (compiled through conversations with many others)
Introduction
The Big PictureOne of the top priorities for Swift right now is compatibility across future Swift versions. Compatibility aims at accomplishing two goals:
Source compatibility means that newer compilers can compile code written in an older version of Swift. This aims to reduce the migration pain that Swift developers face when migrating to a newer Swift version. Without source compatibility, projects face ...
将程序内部的数据结构序列化为一些可交换的数据格式,以及反过来将通用的数据格式反序列化为内部使用的数据结构,这在编程中是一项非常常见的任务。Swift 将这些操作称为编码(encoding)和解码(decoing)。Swift 4 的一个主要特性就是定义了一套标准的编码和解码数据的方法,所有的自定义类型都能选择使用这套方法。
概览
Codable 系统(以其基本“协议”命名,而这个协议其实是一个类型别名)的设计主要围绕三个核心目标;
普遍性 — 它对结构体,枚举和类都适用。
类型安全 — 像是 JSON 这样的可交换格式通常都是弱类型,而你的代码应该要使用强类型数据。
减少模板代码 — 在让自定义类型加入这套系统时,应该让开发者尽可能少地写重复的“适配代码”。编译器应该为你自动生成这些代码。
某个类型通过声明自己遵守 Encodable 和/或 Decodable 协议来表明自己具备被序列化和/或反序列化的能力。这两个协议各自只有一个必须实现的方法 - Encodable 定义了 encode(to:) 用来对值自身进行编码,Decodable 指定了一个初始 ...