轩辕十四

探索科技与创新的个人博客

Schedulers - 调度器


Schedulers 是 Rx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行。

如果你曾经使用过 GCD, 那你对以下代码应该不会陌生:

1
2
3
4
5
6
7
// 后台取得数据,主线程处理结果
DispatchQueue.global(qos: .userInitiated).async {
let data = try? Data(contentsOf: url)
DispatchQueue.main.async {
self.data = data
}
}
阅读全文 »

函数响应式编程


函数响应式编程是种编程范式。它是通过构建函数操作数据序列,然后对这些序列做出响应的编程方式。它结合了函数式编程以及响应式编程。

函数式编程

函数式编程是种编程范式,它需要我们将函数作为参数传递,或者作为返回值返还。我们可以通过组合不同的函数来得到想要的结果。

函数试编程的优点:

  • 灵活
  • 高复用
  • 简洁
  • 易维护
  • 适应各种需求变化

函数式编程 -> 函数响应式编程

1
2
3
4
5
6
7
// 假设用户在进入页面到离开页面期间,总共点击按钮 3 次

// 按钮点击序列
let taps: Array<Void> = [(), (), ()]

// 每次点击后弹出提示框
taps.forEach { showAlert() }
阅读全文 »

Swift 的协议和 Objective-C 的协议不同。Swift 协议可以被用作代理,也可以让你对接口进行抽象 (比如 IteratorProtocolSequence )。它们和 Objective-C 协议的最大不同在于我们可以让结构体和枚举类型满足协议。除此之外,Swift 协议还可以有关联类型。我们还可以通过协议扩展的方式为协议添加方法实现。我们会在面向协议编程的部分讨论所有这些内容。

协议允许我们进行动态派发,也就是说,在运行时程序会根据消息接收者的类型去选择正确的方法实现。

在面向对象编程中,子类是在多个类之间共享代码的有效方式。不过在 Swift 中,Sequence 中的代码共享是通过协议和协议扩展来实现的。通过这么做,Sequence 协议和它的扩展在结构体和枚举这样的值类型中依然可用,而这些值类型是不支持子类继承的。

协议扩展是一种可以在不共享基类的前提下共享代码的方法。协议定义了一组最小可行的方法集合,以供类型进行实现。而类型通过扩展的方式在这些最小方法上实现更多更复杂的特性。

阅读全文 »

实现效果


控件 — UICollectionView


这个动画是用 UICollectionView 实现的,简单讲下 UICollectionView 的工作原理。这里用到的 UICollectionView 也就3部分:ViewController(简称VC)、UICollectionViewCellUICollectionViewLayout

  1. ViewController
    在VC里,UICollectionView 的用法跟 UITableView 的用法类似。这里的初始化方法与 UITableview 有所不同,多了个 collectionViewLayout 属性,每个 collectionView 都会绑定一个 UICollectionViewLayout 对象, collectionView 根据这个 layout 对象来布局 cell

  2. UICollectionViewCell
    这里用的 Cell 实现起来和 UITableViewCell 没什么大区别,我们只要实现它的 initwithFrame 的初始化方法即可,然后实现你想要的布局。

阅读全文 »

和大多数先进语言一样,Swift 拥有不少能被归类于泛型编程下的特性。使用泛型代码,你可以写出可重用的函数和数据结构,只要它们满足你所定义的约束,它们就能够适用于各种类型。比如,像是 ArraySet 等多个类型,实际上是它们中的元素类型就是泛型抽象。我们也可以创建泛型方法,它们可以对输入或者输出的类型进行泛型处理。func identity<A>(input: A) -> A 就定义了一个可以作用于任意类型 A 的函数。某种意义上,我们甚至可以认为带有关联类型的协议是“泛型协议”。关联类型允许我们对特定的实现进行抽象。IteratorProtocol 协议就是一个这样的例子:它所生成的 Element 就是一个泛型。

泛型编程的目的是表达算法或者数据结构所要求的核心接口。比如,考虑内建集合一章中的 last(where:) 函数。将它写为 Array 的一个扩展原本是最明显的选择,但是 Array 其实包含了很多 last(where:) 并不需要的特性。通过确认核心接口到底是什么,也就是说,找到想要实现的功能的最小需求,我们可以将这个函数定义在宽阔得多的类型范围内。在这个例子中,last(where:) 只有一个需求:它需要能够逆序遍历一系列元素。所以,将这个算法定义为 Sequence 的扩展是更好的选择 (我们也可以为 BidirectionalCollection 添加一个更高效的实现)。

阅读全文 »

Swift 支持重载操作符的特性,让我们可以自定义一些简单的计算。
最经典的例子就是两个二维向量之间的计算了。

首先我们定义一个二维向量,并创建两个向量

1
2
3
4
5
6
struct 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)

相加两个向量:

1
let v3 = Vector2D(x: v1.x + v2.x, y: v1.y + v2.y)

这样一次的话,感觉还好。但是遇到复杂的运算的话,这样写感觉就太啰嗦了,这时候重载操作符是最好的选择。

1
2
3
func +(left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
阅读全文 »

字符串索引


大部分编程语言使用整数值对字符串进行下标操作,比如 str[5] 将会返回 str 中的第六个“字符” (这里的“字符”的概念由所操作的编程语言进行定义)。Swift 不允许这么做。为什么?答案可能现在你已经很耳熟了:因为整数的下标访问无法在常数时间内完成 (对于 Collection 协议来说这也是个直观要求),而且查找第 n 个 Character 的操作也必须要对它之前的所有字节进行检查。

String.IndexString 和它的视图所使用的索引类型,它本质上是一个存储了从字符串开头的字节偏移量的不透明值。如果你想计算第 n 个字符所对应的索引,你依然从字符串的开头或结尾开始,并花费 O(n) 的时间。但是一旦你拥有了有效的索引,就可以通过索引下标以 O(1) 的时间对字符串进行访问了。至关重要的是,通过一个已有索引来寻找下一个索引也是很快的,因为你可以从这个已有索引的字节偏移量开始进行查找,而不需要从头开始。正是由于这个原因,按顺序 (前向或者后向) 对字符串中的字符进行迭代是一个高效操作。

阅读全文 »

  • Authors: Michael Ilseman (compiled through conversations with many others)

Introduction


The Big Picture

One of the top priorities for Swift right now is compatibility across future Swift versions. Compatibility aims at accomplishing two goals:

  1. 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 version-lock where all source code in a project and its packages must be written in the same version of Swift. With source compatibility, package authors will be able to maintain a single code base across multiple Swift versions while allowing their users to use a newer version of Swift.
阅读全文 »

将程序内部的数据结构序列化为一些可交换的数据格式,以及反过来将通用的数据格式反序列化为内部使用的数据结构,这在编程中是一项非常常见的任务。Swift 将这些操作称为编码(encoding)和解码(decoing)。Swift 4 的一个主要特性就是定义了一套标准的编码和解码数据的方法,所有的自定义类型都能选择使用这套方法。

概览


Codable 系统(以其基本“协议”命名,而这个协议其实是一个类型别名)的设计主要围绕三个核心目标;

  • 普遍性 — 它对结构体,枚举和类都适用。
  • 类型安全 — 像是 JSON 这样的可交换格式通常都是弱类型,而你的代码应该要使用强类型数据。
  • 减少模板代码 — 在让自定义类型加入这套系统时,应该让开发者尽可能少地写重复的“适配代码”。编译器应该为你自动生成这些代码。
阅读全文 »

Judging by the number of talks, articles and discussions related to reactive programming in Swift, it looks like the community has been taken by the storm. It’s not that the concept of reactiveness itself is a new shiny thing. The idea of using it for the development within the Apple ecosystem had been played with for a long time. Frameworks like ReactiveCocoa have existed for years and did an awesome job at bringing the reactive programming to the Objective-C. However, the new and exciting features of Swift make it even more convenient to go full in on the “signals as your apps’ building blocks” model.

Here at Polidea, we’ve also embraced the reactive paradigm, mostly in the form of RxSwift, the port of C#-originated Reactive Extensions. And we couldn’t be happier! It helps us build more expressive and better-architectured apps faster and easier. Unifying various patterns (target-action, completion block, notification) under a universal API that is easy to use, easy to compose and easy to test has so many benefits. Also, introducing new team members is way easier now, when so much logic is written with methods familiar either from sequences (map, filter, zip, flatMap) or from other languages that Reactive Extensions had been ported to.

阅读全文 »
0%