1. Swift扩展的概念以及重要性:

    1) 扩展的概念:是指向一个已有的类、结构体、枚举添加新的功能(属性、方法、下标等),但不需要修改这些类型的源代码甚至不需要拥有这些类型的源代码;

    2) 和继承的区别:首先扩展可以运用到不止类(还包括结构体和下标,甚至是Int、Double等基本类型,实际上这些基本类型也是用结构体来实现的);

其次,虽然可以通过继承在新的子类中添加更多的功能,但是继承机制比较复杂而有时作者会限制类的继承(比如使用final声明等),但是扩展不受这些约束(比如一个类被声明为final的,虽然其不可被继承,但是仍然可以对其进行扩展):

final class A {
    
}

extension A { // OK! 虽然不能继承但是仍能扩展
    func f() {
        println("haha")
    }
}
这里提一下扩展的语法:

extension 类名 {
    扩展的内容...
}
    3) 扩展的作用:

         i) 特别是在没有权限获取源代码的情况下也可以扩展类型,提高了逆向建模的能力;

         ii) 可以说扩展是一种轻量级的继承;

         iii) 在任何时候都要优先考虑使用扩展(一般Java程序员都会保守地选择继承),这是从简的编程原则,只有当扩展无法满足需求的时候再考略使用继承;

         iv) 扩展在Swift中地位非常重要,很多Swift API以及一些Swift的基本类型都是通过扩展实现的,比如String的很多方法就是通过扩展实现的;

    4) 可以对基本类型进行扩展,比如Int、String、Double、Character等,因为这些基本类型底层都是用结构体包装的!

    5) Swift允许扩展的内容:

         i) 对于值类型(结构体和枚举)可以扩展静态存储属性,但是对于类类型则不能扩展静态存储属性;

         ii) 对于任何类型都不能扩展实例存储属性;

         iii) 可以扩展计算属性(实例、静态都行);

         iv) 可以扩展方法(实例、静态都行);

         v) 可以扩展构造器;

         vi) 可以扩展下标;

         vii) 可以扩展嵌套类;

         viii) 可以扩展使其适配一个或多个协议;

    6) 扩展的最大亮点:在定义扩展后全局有效,即那些在扩展前定义的对象也可以使用扩展出的新功能;


2. 扩展静态存储属性:

    1) 只对于值类型成立;

    2) 举例:

extension Int {
    static var sta_var = 90 // OK! Int是值类型的结构体
}

class A {
    
}

//extension A {
//    static var test = 11 // Bad! 不能扩展类类型的静态存储属性
//}

struct B {
    
}

extension B {
    static var test = 11 // OK! 结构体类型可以
}

enum C {
    
}

extension C {
    static var test = 22 // OK! 枚举类型也是值类型,同样也可以扩展静态存储属性
}
    3) 但是对于任何类型都不能扩展实例存储属性!


3. 扩展计算属性:!注意值类型和枚举类型之间的区别

extension Int {
    var errMessage: String { // 扩展实例的只读计算属性
        switch self {
        case -7: return "没有数据"
        case -6: return "日期格式有误"
        case -5: return "内容格式有误"
        case -4: return "ID为空"
        case -3: return "数据访问失败"
        case -2: return "空间不足"
        case -1: return "用户不存在"
        default: return ""
        }
    }
}

println((-3).errMessage) // 数据访问失败,注意使用括号否则编译解析会有问题


struct A {
    
}

extension A {
    static var x = 10 // 扩展静态存储属性
    var y: Int { // 扩展实例可读可写计算属性对静态存储属性进行维护
        get {
            return A.x
        }
        set {
            A.x = newValue
        }
    }
}

println(A.x) // 10
var a = A()
println(a.y) // 10
a.y = 30
println(A.x) // 30

extension Double { // 模拟单位表示法
    var km: Double { return self * 1_000.0 }
    var m: Double { return self }
    var cm: Double { return self / 100.0 }
    var mm: Double { return self / 1_000.0 }
}

var some_km = 5.0.km
var some_m = 3.9.m
var some_cm = 90.3.cm
var some_mm = 33.23.mm
println(some_km) // 5000.0
println(some_m) // 3.9
println(some_cm) // 0.903
println(some_mm) // 0.03323

class B {
    
}

extension B {
    class var test: Int { // 扩展静态计算属性
        return 23
    }
}

4. 扩展构造器:

对于结构体可以扩展普通构造器和代理构造器,但是对于类只能扩展便利构造器但不能扩展指定构造器!

struct A {
    var a = 15
    var b = 20
    
    init(a: Int, b: Int) {
        self.a = a
        self.b = b
    }
}

extension A { // 对于结构体既可以扩展普通构造器也可以扩展代理构造器
    init(a: Int) {
        self.a = a
    }
    
    init() {
        self.init(a: 23, b: 88)
    }
}

extension A { // 可以连续扩展任意多次
    init(s: String) {
        self.init()
    }
}

class B {
    var a: Int
    var b: Int
    
    init(a: Int, b: Int) {
        self.a = a
        self.b = b
    }
}

extension B { // 对于类只能扩展便利构造器不能扩展指定构造器,否则会报错!
    // !由于类只能扩展便利构造器而不能扩展指定构造器,因此就不能用super调用父类构造器了!
    convenience init() {
        self.init(a: 10, b: 20)
    }
}


5. 扩展方法:

按照之前讲过的定义方法的规则可以随意扩展:

extension Double {
    static let rate = 3.773 // 结构体可以扩展静态存储结构
    
    func getTotal() -> Double { // 扩展实例方法
        return Double.rate * self
    }
    
    static func computeTotal(amount: Double) -> Double { // 扩展静态方法
        return rate * amount
    }
    
    mutating func doubleIt() { // 要改变结构体本身的内容需要变异!
        self = self * 2
    }
}

class A { // 注意!类只支持静态计算属性不支持静态存储属性
    var value: Double = 234.32
}

// 相应的类类型的版本
extension A {
    class var rate: Double {
        return 3.231
    }
    
    func getTotal() -> Double {
        return value * A.rate
    }
    
    class func computeTotal(amount: Double) -> Double {
        return rate * amount
    }
    
    func doubleIt() {
        value = value * 2
    }
}
一个扩展方法的非常有趣的例子:为Int扩展一个方法,使用Int的数值n重复n次动作,这个动作作为闭包作为参数传入扩展的方法

extension Int {
    func rep(task: () -> ()) {
        for _ in 0..<self {
            task()
        }
    }
}

3.rep { println("haha") }


6. 扩展下标:

就跟普通定义下标一样,这里介绍两个扩展String和Int下标的有趣的例子:

扩展String下标,用来模仿C语言字符数组随机访问的功能

extension String {
    subscript(index: Int) -> String { // 返回的字符用String包装
        if index < 0 || index + 1 > countElements(self) {
            return ""
        }
        
        var i = 0
        for char in self { // 从字符串中取出的元素是Character类型的
            if i == index {
                return String(char) // 需要包装成String类型
            }
            i++
        }
        
        return ""
    }
}

println("abc"[2]) // c
扩展Int下标,获得从低到高的第n位数字,第0位是最低位:

extension Int {
    subscript(index: Int) -> Int {
        var base = 1
        for _ in 0..<index {
            base *= 10
        }
        
        return (self / base) % 10
    }
}

println(23423[2]) // 4


6. 扩展嵌套类型:

就和定义普通的嵌套类型一样,这里介绍一下在Character中扩展一个枚举类型,用于对字符的类型进行分类(元音、辅音等):

extension Character {
    enum Kind: String {
        case Vowel = "Vowel"
        case Consonant = "Consonant"
        case Other = "Other"
    }
    
    var kind: Kind {
        switch String(self).lowercaseString {
        case "a", "e", "i", "o", "u": return .Vowel
        case "b", "c", "d", "f", "g": return .Consonant
        default: return .Other
        }
    }
}

println(Character("I").kind.rawValue) // Vowel


7. 扩展适配协议:

可以扩展一个类型使其匹配一个或多个协议,这里只介绍其语法:

extension Type: Protocol1, Protocol2... {
    ...
}

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐