本篇將詳細總結介紹Swift擴展的用法;
擴展就是為一個已有的類、結構體、枚舉類型或者協(xié)議類型添加新功能。這包括在沒有權限獲取原始源代碼的情況下擴展類型的能力(即逆向建模 )
主要內(nèi)容:
1.理解擴展
2.擴展的基本使用
3.嵌套類型
4.擴展系統(tǒng)類庫
一、理解擴展
1.1擴展特點:
1.擴展和 Objective-C 中的分類類似。(與 Objective-C 不同的是,Swift 的擴展沒有名字。)
3.擴展可以為一個類型添加新的功能,但是不能重寫已有的功能
1.2擴展功能:
1、添加計算型實例屬性和計算型類型屬性。
2、定義實例方法和類型方法
3、提供新便利構造器和便利析構器
4、定義下標
5、定義和使用新的嵌套類型
6、使一個已有類型符合某個協(xié)議”
1.3使用注意:
1.不可以添加存儲屬性,也不可以為已有屬性添加屬性觀察器
2.擴展中不能為類添加新的指定構造器,因為指定構造器和析構器必須由原始的類來實現(xiàn)
3.擴展可以為一個類型添加新的功能,但是不能重寫已有的功能。
4.通過擴展為一個已有類型添加新功能,那么新功能對該類型的所有已有實例都是可用的,即使它們是在這個擴展定義之前創(chuàng)建的。
二、擴展的基本使用
定義如下的Point 、Size、Rectangle,并對其進行擴展。
struct Point{
var x = 0.0
var y = 0.0
}
struct Size{
var width = 0.0
var height = 0.0
}
class Rectangle {
var origin:Point = Point()
var size = Size()
init (origin:Point, size: Size){
self.origin = origin
self.size = size
}
}
2.1.擴展屬性
擴展可以添加新的計算型屬性,但是不可以添加存儲型屬性,也不可以為已有屬性添加屬性觀察器
extension Rectangle{
//注意:擴展不能擴展存儲型屬性
//var center:Point = Point() //報錯
//只能擴展計算型屬性
var center: Point {
get {
let center_x = origin.x + size.width/2
let center_y = origin.y + size.height/2
return Point(x: center_x, y: center_y)
}
set{
origin.x = newValue.x - size.width/2
origin.y = newValue.y - size.height/2
}
}
}
let rect1 = Rectangle(origin: Point(x:0,y:0), size: Size(width: 100, height: 100))
print(rect1.center) //Point(x: 50.0, y: 50.0)
rect1.center = Point(x: 0, y: 0)
print(rect1.center) //Point(x: 0.0, y: 0.0)
2.2.擴展方法
擴展可以為已有類型添加新的實例方法和類型方法。
extension Rectangle{
//注意:這里直接修改了屬性,如果是結構體Struct,不能直接這樣修改
//func之前需要使用 mutating
func translate(x:Double , y:Double){
self.origin.x += x
self.origin.y += y
}
}
let rect2 = Rectangle(origin: Point(x:0,y:0), size: Size(width: 100, height: 100))
rect2.translate(x: 100, y: 100)
print(rect2.center) //Point(x: 150.0, y: 150.0)
2.3.擴展構造器
擴展能為類添加新的便利構造器,但是它們不能為類添加新的指定構造器或析構器。指定構造器和析構器必須總是由原始的類實現(xiàn)提供.
extension Rectangle{
//注意:在擴展中添加了構造函數(shù),必須是便利構造函數(shù),其中調(diào)用指定構造函數(shù)
convenience init(center:Point, size:Size) {
let origin_x = center.x - size.width/2
let origin_y = center.y - size.height/2
//便利構造函數(shù)必須調(diào)用指定構造函數(shù)
self.init(origin:Point(x: origin_x, y: origin_y),size:size)
}
}
let rect3 = Rectangle(center: Point(x:200, y:200), size: Size(width: 100, height: 100))
注意1:如果你使用擴展提供了一個新的構造器,你依舊有責任確保構造過程能夠讓實例完全初始化。
注意2:如果你使用擴展為一個值類型添加構造器,同時該值類型的原始實現(xiàn)中未定義任何定制的構造器且所有存儲屬性提供了默認值,那么我們就可以在擴展中的構造器里調(diào)用默認構造器和逐一成員構造器。
2.4.擴展下標
擴展可以為已有類型添加新下標。下面的例子為Swift內(nèi)建類型Int添加了一個整型下標。該下標 [n] 返回十進制數(shù)字從右向左數(shù)的第n個數(shù)字:
extension Int {
subscript(digitIndex: Int) -> Int {
var decimalBase = 1
for _ in 0..<digitIndex {
decimalBase *= 10
}
return (self / decimalBase) % 10
}
}
//測試代碼:
print(746381295[3]) //1
print(746381295[6]) //6
三、嵌套類型
擴展可以為已有的類、結構體和枚舉添加新的嵌套類型。在下面的示例中,Rectangle中就嵌套一個枚舉類型,用以獲取矩形的各個定點坐標。
extension Rectangle{
enum Vertex:Int {
case TopLeft
case TopRight
case BottomLeft
case BottomRight
}
//擴展出一個方法來獲取各個頂點坐標
func pointAtVertex(v:Vertex) -> Point{
switch v {
case .TopLeft:
return origin
case .TopRight:
return Point(x: origin.x + size.width, y: origin.y)
case .BottomLeft:
return Point(x: origin.x, y: origin.y + size.height)
case .BottomRight:
return Point(x: origin.x + size.width, y: origin.y + size.height)
}
}
//擴展下標
subscript (index:Int) ->Point{
assert(index >= 0 && index<4,"out of range")
//修改枚舉的原始值是Int類型,而這里??使用rowValue方法構建了枚舉型
return pointAtVertex(v: Vertex(rawValue: index)!) //已經(jīng)使用了斷言,這里使用強制解包
}
}
//測試代碼:
let rect4 = Rectangle(origin: Point(x:0,y:0), size: Size(width: 100, height: 100))
let point1 = rect4.pointAtVertex(v: .TopRight)
print(point1) //Point(x: 100.0, y: 0.0)
let point2 = rect4.pointAtVertex(v: Rectangle.Vertex.BottomRight)
print(point2) //Point(x: 100.0, y: 0.0)
let point3 = rect4[2]
print(point3) //Po
四、擴展系統(tǒng)類庫
4.1.擴展Double
擴展Double,為其添加計算型屬性,提供與距離單位協(xié)作的基本支持。
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 ft: Double { return self / 3.28084 }
}
//測試代碼:
let distance1 = 25.4.mm
print("distance1 is \(distance1) meters") //distance1 is 0.0254 meters
let distance2 = 42.mm + 1.km
print("disatance2 is \( distance2) meters") //disatance2 is 1000.042 meters
4.2.擴展Int類
擴展Int,為其添加平方、立方、范圍判斷等方法。
extension Int{
//平方運算
var square:Int{
return self * self
}
//立方運算
var cube:Int{
return self * self * self
}
//判斷整型是否在某個范圍內(nèi)
func inRange(closedLeft:Int, opendRight:Int) -> Bool{
return self >= closedLeft && self < opendRight
}
//通過傳入一個閉包參數(shù),簡單的實現(xiàn)循環(huán)操作
func repetitions(task: () -> Void){
for _ in 0...10{
//執(zhí)行閉包
task()
}
}
}
//測試代碼:
var tempNum = 10;
tempNum.square() //100
tempNum.inRange(closedLeft: 10, opendRight: 100) //false
tempNum.repetitions {
print(tempNum)
}