免费开源的iOS开发学习平台

Swift:17 扩展

扩展就是为一个已有的类、结构体、枚举类型或者协议类型添加新功能。这包括在没有权限获取原始源代码的情况下扩展类型的能力(即逆向建模)。扩展和Objective-C中的类别类似。(与Objective-C不同的是,Swift的扩展没有名字。)

扩展语法

使用关键字extension来声明扩展:

extension SomeType{
    // 为 SomeType 添加的新功能写到这里
}

可以通过扩展来扩展一个已有类型,使其遵守一个或多个协议。在这种情况下,无论是类还是结构体,协议名字的书写方式完全一样:

extension SomeType: SomeProtocol, AnotherProctocol {
    // 协议实现写到这里
}

计算型属性

扩展可以为已有类型添加计算型实例属性和计算型类型属性。下面的例子为Swift的内建Int类型添加了四个计算型实例属性,来演示存储单位Byte、KB、MB和GB之间的换算关系。这些属性是只读的计算型属性,为了更简洁,省略了get关键字。它们的返回值是Int,而且可以用于所有接受Int值的数学计算中:

extension Int{
    var B: Int { return self  }
    var KB : Int { return self * 1024 }
    var MB: Int { return self * 1024*1024 }
    var GB: Int { return self * 1024*1024*1024 }
}

let fileSize = 4.KB
print("1KB = \(fileSize) Byte")

let bigFileSize = 4.GB
print("1GB = \(bigFileSize) Byte")

let sum = 1024.KB + 3.MB

print("1024B + 3KB = \(sum) Byte")

代码执行结果如下图。

构造器

扩展可以为已有类型添加新的构造器。这可以让你扩展某个类型,将你自己的定制类型作为其构造器参数,或者提供该类型的原始实现中未提供的额外初始化选项。扩展能为类添加新的便捷构造器,但是它们不能为类添加新的指定构造器或析构器。指定构造器和析构器必须总是由原始的类实现来提供。下面演示通过扩展的方式为Rect结构体添加便捷构造器的过程。

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}

struct Rect {
    var origin = Point()
    var size = Size()
    func toString()  {
        print("[origin:(\(origin.x),\(origin.y)),size:(\(size.width),\(size.height))]")
    }
}
extension Rect{
    init(center: Point, size: Size) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: Point(x: originX, y: originY), size: size)
    }
}

let r1 = Rect()
r1.toString()

let r2 = Rect(origin: Point(x:10,y:10), size: Size(width: 6.0, height: 6.0))
r2.toString()

let r3 = Rect(center: Point(x:13,y:13), size: Size(width: 6.0, height: 6.0))
r3.toString()

代码执行结果截图如下图所示。

方法

扩展可以为已有类型添加新的实例方法和类型方法。下面的例子为Int类型添加了一个名为repetitions的实例方法,通过添加该方法,可以重复执行一段代码。

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
}
//调用三次闭包函数
3.repetitions({
    print("Hello!")
})
//Hello!
//Hello!
//Hello!

//如果函数最后一个参数是闭包,也可以使用尾随闭包让调用更加简洁
3.repetitions {
    print("Goodbye!")
}
//Goodbye!
//Goodbye!
//Goodbye!

可变实例方法

通过扩展添加的实例方法也可以修改该实例本身。结构体和枚举类型中修改self或其属性的方法必须将该实例方法标注为mutating,正如来自原始实现的可变方法一样。下面代码演示整型自增。

extension Int {
    mutating func addOne() {
        self +=  1
    }
}
var someInt = 3
someInt.addOne() 
//someInt现在的值为4

下标

扩展可以为已有类型添加新下标。下面这个例子为Swift类型Int添加了一个整型下标。该下标[n]返回十进制数字从右向左数的第n个数字:

123456789[

123456789[1] 返回 8

……以此类推。

extension Int {
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex {
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}
746381295[0]  // 返回 5

746381295[1] // 返回 9

746381295[2] // 返回 2

746381295[8] // 返回 7

746381295[9] // 返回 0

嵌套类型

扩展可以为已有的类、结构体和枚举添加新的嵌套类型,下面示例演示了通过扩展Int类型,来判断Int的值是正数、零还是负数三种情况。

extension Int {
    enum Kind {
        case Negative, Zero, Positive
    }
    var kind: Kind {
        switch self {
        case 0:
            return .Zero
        case let x where x > 0:
            return .Positive
        default:
            return .Negative
        }
    }
}

func printIntegerKinds(_ numbers: [Int]) {
    for number in numbers {
        switch number.kind {
        case .Negative:
            print("- ", terminator: "")
        case .Zero:
            print("0 ", terminator: "")
        case .Positive:
            print("+ ", terminator: "")
        }
    }
    print("")
}

printIntegerKinds([3, 19, -27, 0, -6, 0, 7])

代码运行结果如下图所示。

示例代码

https://github.com/99ios/23.18