- Swift中的扩展,有点类似于OC中的分类(Category)
- 扩展可以为
枚举
、结构体
、类
、协议
添加新功能
□ 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等等 - 扩展不能办到的事情:
□ 不能覆盖原有的功能
□ 不能添加存储属性,不能向已有的属性添加属性观察器
□ 不能添加父类
□ 不能添加指定初始化器,不能添加反初始化器
......
计算属性、下标、方法、嵌套类型
- 添加计算属性(计算属性的本质就是方法)
extension Double {
var km: Double { self * 1_000.0}
var m: Double { self }
var dm: Double { self / 100.0 }
var cm: Double { self / 10.0 }
var mm: Double { self / 1_000.0 }
}
- 添加下标
Element
是Array
原有的泛型,可以通过查看Array
得知
extension Array {
subscript(nullable idx: Int) -> Element? {
if (startIndex ..< endIndex).contains(idx) {
return self[idx]
}
return nil
}
}
- 添加 方法、嵌套类型
extension Int {
func repetitions(task: () -> Void) {
for _ in 0.. Int {
self = self * self
return self
}
enum Kind {
case negative
case zero
case positive
}
var kind: Kind {
switch self {
case 0:
return .zero
case let x where x > 0:
return .positive
default:
return .negative
}
}
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..
协议、初始化器
- 如果希望
自定义初始化器
的同时,编译器也能够生成默认初始化器
□ 可以在扩展(extension)
中编写自定义初始化器
-
required
初始化器不能写在扩展中 - 扩展协议
class Person {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
}
extension Person: Equatable {
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.age == rhs.age && lhs.name == rhs.name
}
// 便捷初始化器
convenience init() {
self.init(age: 0, name: "")
}
}
- 扩展初始化器
struct Point {
var x: Int = 0
var y: Int = 0
}
extension Point {
init(_ point: Point) {
self.init(x: point.x, y: point.y)
}
}
var p1 = Point()
var p2 = Point(x: 10, y: 20)
var p3 = Point(x: 10)
var p4 = Point(y: 20)
var p5 = Point(p2)
协议
- 如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议,可以通过扩展来让让它遵守这个协议
protocol MyProtocol {
func test()
}
class test {
func test() {
print("name")
}
}
extension test: MyProtocol {}
- 编写一个函数,判断一个整数是否为奇数
□ 一般情况下我们会这样写:
func isOdd(_ i: Int) -> Bool {
(i % 2) != 0
}
print(isOdd(4))
/*输出结果*/
false
大家要清楚,上面的写法是不严谨的,如果传入一个UInt
呢?
那我们应该怎样去处理呢?
由于所有的整数都遵守
BinaryInteger
协议,所有我们可以:
□ 第一种方法,使用泛型,并限定泛型
func isOdd(_ i: T) -> Bool {
(i % 2) != 0
}
□ 给BinaryInteger
协议添加扩展,这种方式是比较好的
extension BinaryInteger {
func isOdd() -> Bool {
(self % 2) != 0
}
}
print(3.isOdd())
/*输出结果*/
true
- 扩展可以给协议提供默认实现,也间接实现可选协议的效果
- 扩展可以给协议补充协议中从未声明过的方法
protocol MyProtocol {
func fun1()
}
extension MyProtocol {
func fun1() {
print("MyProtocol fun1")
}
func fun2() {
print("MyProtocol fun2")
}
}
我们都知道,只要遵守了协议,就必须实现协议中声明的方法;但是我们可以在协议的扩展中提供默认实现,这样就可以实现可选协议:
class Person: MyProtocol {}
var p = Person()
p.fun1() // MyProtocol fun1
p.fun2() // MyProtocol fun2
当然,如果我们再类里面去实现协议的方法,那么执行的还就执行类里面的实现:
class Person: MyProtocol {
func fun1() {
print("Person fun1")
}
func fun2() {
print("Person fun2")
}
}
var p = Person()
p.fun1() // Person fun1
p.fun2() // Person fun2
这里有一个要注意一下:
如下,p
声明为遵守MyProtocol
协议类型,实际是Person
;但是在调用方法的时候,没有在MyProtocol
协议中声明但是在扩展中有默认实现的方法,对象p
去调用的话,会执行协议扩展中的默认方法。
var p: MyProtocol = Person()
p.fun1() // Person fun1
p.fun2() // MyProtocol fun2
这是因为,fun2
在协议中没有声明,那么编译器就不确定遵守它的类是否有实现该方法,所有优先执行协议扩展中实现的默认方法。
如果var p = Person()
,这样写,并没有告诉编译器是遵守MyProtocol
协议的对象,只是告诉编译器是Person
对象,所以优先执行Person
里面的方法。
泛型
class Stack {
var elements = [E]()
func push(_ element: E) {
elements.append(element)
}
func pop() -> E {
elements.removeLast()
}
func size() -> Int {
elements.count
}
}
// 扩展中依然可以使用原类型中的泛型类型
extension Stack {
func top() -> E {
elements.last!
}
}
// 符合条件才扩展
extension Stack : Equatable where E : Equatable {
static func == (left: Stack, right: Stack) -> Bool {
left.elements == right.elements
}
}