阅读 66

Swift进阶(十五)扩展(Extension)

  • 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 }
}
  • 添加下标
    ElementArray原有的泛型,可以通过查看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..<self {
            task()
        }
    }
    
    mutating func square() -> 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..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
    
}

协议、初始化器

  • 如果希望自定义初始化器的同时,编译器也能够生成默认初始化器
    □ 可以在扩展(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呢?

image.png

那我们应该怎样去处理呢?
由于所有的整数都遵守BinaryInteger协议,所有我们可以:
□ 第一种方法,使用泛型,并限定泛型

func isOdd<T: BinaryInteger>(_ 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<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 == (left: Stack, right: Stack) -> Bool {
        left.elements == right.elements
    }
}

作者:Jax_YD

原文链接:https://www.jianshu.com/p/af96aecf6372

文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐