陈斌彬的技术博客

Stay foolish,stay hungry

Swift-扩展

扩展(extension)

扩展是向一个已有的类、结构体或枚举类型添加新的功能。在swift中扩展是没有名字的,

但在Objective-C中Category是有名字的,而且只能扩展类(类别)

如在Swift中扩展是这么写的:

extension String {  
  func reverseString() -> String {  
    // do something if necessary   
  }  
}  

在Objective-C中,是这么写的:  
@interface NSString (ReverseStringExtension)   
- (NSString *)reverseString; // implementent in .m file  
@end   

Swift中扩展可以:

  1. 添加计算实例属性(computed property)和计算类属性
  2. 定义实例方法和类方法
  3. 提供新的构造器
  4. 定义下标(subscript)
  5. 定义和使用新的嵌套类型
  6. 使一个遵守某个接口

扩展语法(Extension syntax)

声明扩展的关键字extension

extension SomteType {  
 // add sth  
}  

可以扩展类型时让类型遵守协议:  
extension SomteType : SomeProtocol, OtherProtocol {  
  // do sth if necessary  
}  

扩展类型,添加计算属性:

// 添加长度单位属性  
extension Double {  
  var km: Double {  
    return selfself * 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 oneInch = 25.4.mm  
println("One inch is \(oneInch) meters") // prints One inch is 0.0254 meters  

let threeFeet = 3.ft  
println("Three feet is \(threeFeet) meters") // prints Three feet is 0.914399970739201 meters  

let sum = 10.4.km + 122.5.km // 这么写法是不是很方便就能进行转换?Yes  

注意:

扩展可以添加新的计算属性,但不能添加存储属性,也不能向已有属性添加属性观察。

给值类型扩展新的构造器。

如果使用扩展给值类型添加一个构造器,如果该类型所有属性已经有默认值,但没有定制任何构造器,此时我们可以调用默认的构造器和成员逐一构造器。

struct Size {  
  var width = 0.0  
  var height = 0.0  
}  

struct Point {  
  var x = 0.0  
  var y = 0.0  
}  

struct Rect {  
  var origin = Point()  
  var size = Size()  
}  

// 这里因为Rect结构体都提供了属性的默认值,它可以自动会有一个默认的构造器和一个成员逐一的构造器,  
// 即:init()方法和init(origin:Point, size: Size)  
// 那么我们可以直接使用:  
let defaultRect = Rect() // 调用默认构造器  
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0), size: Size(width: 5.0, height: 5.0))  

// 下面我们给Rect扩展一个构造器  
extension Rect {  
  init(center: Point, size: Size) {  
     let originX = center.x - size.width / 2.0  
     let originY = center.y - size.height / 2.0  

     // 调用本类自动得到的成员逐一构造器  
     self.init(origin: Point(x: originX, y: originY), size: size)  
  }  
}  

扩展方法:类方法(引用类型)、静态方法(值类型)和实例方法、修改实例方法

extension Int {  
  // 参数是一个单类型的闭包,没有参数,没有返回值的闭包  
  func repetions(task: () -> ()) {  
    for i in 0..self {  
      task()  
    }  
  }  
  // 仅是例子,这是不好的设计  
  static func multiply(a: Int, b: Int) -> Int {  
    return a * b  
  }    

  // 要修改Self,就需要是可改类型方法,需要加上关键字mutating  
  mutating func square() {  
    self = selfself * self  
  }  
}  

let number = 4  
number.repetions { // 使用了trailing closure  
  println("test extension")  
}  
// test extension  
// test extension  
// test extension  
// test extension  

println(Int.multiply(2, 3)) // prints 6  
println(3.square()) // prints 9  

下标(subscripts)

扩展可以向一个已有类型添加新下标。如下:

extension Int {  
// 下标[n]会返回十进制数字从右向左第n个数字  
  subscript(index: Int) -> Int {  
    var decimalBase = 1   
    for _ in 1...index {  
      decimalBase *= 10  
    }  
    return (self / decimalBase) % 10  
  }  
}  

println(746381295[0])  
// returns 5  
println(746381295[1])  
// returns 9  
println(746381295[2])  
// returns 2  
println(746381295[8])  
// returns 7  

总结:个人认识扩展是很好用的功能,在项目中,会把通常的基础辅助方法扩展到已有类中, 这样可以方便整个工程的使用。

Resource Reference