Swift
中的扩展,类似于OC
中的分类Category
-
扩展可以为枚举、类、结构体、协议添加新功能
- 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等等
-
扩展不能办到的事情
- 不能覆盖原有的功能
- 不能添加存储属性,不能向已有的属性添加属性观察器
- 不能添加父类
- 不能添加指定初始化器,不能添加反初始化器
- ......
例子🌰:为Double
类型增加扩展,新增只读的计算属性,计算属性本质是方法,相当于为Double
新增方法
extension Double {
var second: Double { self }
var minute: Double { self / 60.0 }
var hour: Double { self / 3600.0 }
}
var s = 1200.0 //秒
print(s.second) // 1200.0秒
print(s.minute) // 20.0分钟
print(s.hour) // 0.3333333333333333小时
print(3600.0.minute) //60.0分钟
数组Array
本身不提供下标判断,因此不小心容易造成数组越界,导致程序奔溃。
var arr = [10, 20, 30]
var age = arr[-1] //运行报错,数组越界
var age2 = arr[10] //运行报错,数组越界
为数组Array
扩展一个下标,实现下标判断,如果越界,就返回nil
extension Array {
subscript(nullable idx: Int) -> Element? {
if (startIndex..<endIndex).contains(idx) {
return self[idx]
}
return nil
}
}
var arr = [10, 20, 30]
var age = arr[nullable: -1]
print(age as Any) // nil
为类型Int
扩展了一系列实现
extension Int {
//声明一个调用多次实现外部传入函数的扩展
func repeats(task: () -> Void) {
for _ in 0..<self {
task()
}
}
//实现平方计算
mutating func square() -> Int {
self = self * self
return self
}
//嵌套一个enum枚举
enum Kind {
case negative, zero, positive
}
//增加计算属性,判断正数、负数、0
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..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
3.repeats {
print("lalalalla")
}
var number = 4
print(number.square()) // 16
print(Int.Kind.negative) // negative
print(5.kind) // positive
print(0.kind) // zero
print((-5).kind) // negative
var number2 = 123
print(number2[0]) // 3
print(number2[1]) // 2
print(number2[2]) // 1
print(number2[4]) // 0
为Person
类增加扩展,增加Equatable
协议实现==
判断方法,增加一个便捷初始化器
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: "")
}
}
为结构体Point
添加扩展,增加一个初始化器
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)
var p3 = Point(y: 20)
var p4 = Point(x: 10, y: 20)
//上面4种初始化,都是编译器自动提供了
//这是扩展的,允许传入一个Point变量进行初始化
var p5 = Point(p4)
如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议,可以通过扩展来实现遵守这个协议
protocol TestProtocol {
func test()
}
class TestClass {
func test() {
print("test")
}
}
extension TestClass: TestProtocol {
}
为所有的整数扩展一个判断奇偶的方法:
因为整数有````Int、``UInt
、Uint8
、Uint16
、Uint32
...如果只是单独的写一个方法,那就得考虑到传参的问题。
我们这好到整数的共同点,它们都遵守BinaryInteger
协议,因此可以对BinaryInteger
协议进行扩展。
extension BinaryInteger {
func isOdd() -> Bool {
self % 2 != 0
}
}
print(8.isOdd()) // false
print(11.isOdd()) // true
print((-5).isOdd()) // true
print((-4).isOdd()) // false
print(UInt8(7).isOdd()) // true
- 扩展可以给协议提供默认实现,也间接实现可选协议的效果
- 扩展可以给协议补充协议中从未声明过的方法
protocol TestProtocol {
func test1()
}
extension TestProtocol {
func test1() {
print("TestProtocol - test1")
}
//给协议补充test2方法
func test2() {
print("TestProtocol - test2")
}
}
class TestClass: TestProtocol {
//内部不实现test1,并不会报错,因为在协议扩展中实现了
}
var cls = TestClass()
cls.test2() //可以调用test2方法
扩展里面依然可以使用原类型的泛型
class Stack<E> {
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 == (lhs: Stack<E>, rhs: Stack<E>) -> Bool {
lhs.elements == rhs.elements
}
}
网友评论