Swift 扩展(extension)

扩展就是向一个已有的类、结构体、枚举类型或者协议类型添加新功能(functionality)。Swift中的扩展就类似于ObjC中的分类(事实上在其他高级语言中更多的称之为扩展而非分类),但是它要比分类强大的多. 
Swift 中的扩展可以:
添加计算型属性和计算型静态属性
定义实例方法和类型方法
提供新的构造器
定义下标
定义和使用新的嵌套类型
使一个已有类型符合某个协议
注意:
扩展可以对一个类型添加新的功能,但是不能重写已有的功能。

在 Swift 中,你甚至可以对一个协议(Protocol)进行扩展,提供协议需要的实现,或者添加额外的功能能够对合适的类型带来额外的好处。

扩展语法

声明一个扩展使用关键字extension:
extension SomeType {
    // 加到SomeType的新功能写到这里
}
添加属性和方法

//添加属性和方法  扩展Double类型来解决津巴布韦货币兑换问题.
extension Double{

    //1)扩展增加类型属性
    static var name = "扩展Double"
    
    //通用汇率
    static var factor:Double{
           return 12_500_000_000_000
    }
    
    //转换为人命币
    var CNY:Double{
        return self / Double.factor
    }
    
    //转换为美元
    var USD:Double{
        return (self / Double.factor) / 6.7
    }
    
    //转换为欧元
    var EUR:Double{
        return (self / Double.factor) / 8.8
    }
    
    //统计当前货币中零的个数
    var Zeros:Int{
    
        let strValue = "\(self)"
        //这里使用 UTF8字符集统计字符串的长度
        return strValue.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) - 3
    }
    
    //增加实例方法
    func description() ->String{
        return Double.name
    }
    
    //2)扩展增加类型方法
    static func whoAmI() ->String{
        return "我是\(name) 我的类型是\(self)"
    }

}

func testOne(){
    
        var money:Double = 100_000_000_000_000
        print("津巴布韦的货币: \(money)")
        print("津巴布韦货币兑换为人命币: \(money.CNY)")
        print("津巴布韦的货币兑换为美元: \(money.USD)")
        print("津巴布韦的货币兑换为欧元: \(money.EUR)")
        print("当前的货币是: \(money.description)")
        
        print(Double.whoAmI())
        print("当前的津巴布韦货币含有 \(money.Zeros)")
        print("当前的津巴布韦货币含有: \(100_000_000_000_000.Zeros)")
        
        /*
        
        津巴布韦的货币: 100000000000000.0
        津巴布韦货币兑换为人命币: 8.0
        津巴布韦的货币兑换为美元: 1.19402985074627
        津巴布韦的货币兑换为欧元: 0.909090909090909
        当前的货币是: 100000000000000.0
        我是扩展Double 我的类型是Double
        当前的津巴布韦货币含有 14
        当前的津巴布韦货币含有 14
        
        代码分析:
        
        1:上述代码部分,我们使用了extension扩展了Swift内置类型 Double的功能.
        2:添加了静态计算属性,如factor属性.添加了计算属性CNY,EUR等.
        3:extension不能够扩展实例的存储属性,比如我们的name属性,如果去掉static,则会报错,但是我们可以增加类型的存储属性.
        4:我们为Double增加了类型方法( whoAmI())也增加了实例方法(description()).
        5:扩展出来的属性和方法不仅可以通过变量名调用,甚至可以直接使用字面量.如100_000_000_000_000.Zeros.
        6:扩展不能够给已有属性增加属性观察器.
        
        */
        
} 
添加构造器
其实构造器就是一个特殊的方法,所以扩展构造器方法就是添加方法,不过要注意两点:
   1:如果扩展类类型,我们只能够增加便捷构造器,而不能够增加指定构造器和析构器.
   2:对于值类型,比如结构体,枚举,在扩展其构造器时,务必保证所有的属性都被初始化.

//守夜人的佩剑
struct Sword{

    var length = 0.5
    var materials:String = "由普通钢铸造而成"
}

//守夜人类
class NightWatcher{

    var sword:Sword
    var name:String
    
    //使用指定构造器初始化属性
    init(name: String,sword:Sword){
        self.name = name
        self.sword = sword
    }
    
    //便捷构造器
    convenience init(){
        self.init(name:"守夜人",sword:Sword())
    }
}

//扩展剑的质量 凡是"异鬼克星"都使用龙晶打造,只有龙晶宝剑可以杀死异鬼
extension Sword{

    init(brand:String){
    
        if brand == "异鬼克星"{
            //调用结构体Sword的成员构造器
            self.init(length:1 , materials: "由龙晶铸造")
        }else{
            //调用结构体Sword的默认构造器,注意:只有结构体的所有属性都有默认值时才可以使用其默认构造器
            self.init()
        }
    }
    
    var description:String{
        return "长\(length)米 \(materials)"
    }
}

//扩展NightWatcher类
extension NightWatcher{

    //扩展类的构造器,只能够扩展便捷构造器,所以如果删除前面的convenience将报错
    convenience init(name:String){
    
        if name == "Tarly"{
            //调用该类固有的指定构造器
            self.init(name: name, sword:Sword(brand: "异鬼克星"))
        }else{
            //调用便捷构造器
            self.init()
        }
    }
    
    func say(){
        print(" 我是\(name) 我的剑\(sword.description)")
    }
    
}
func testTwo(){
    
        //路人甲出场
        var somebody = NightWatcher()
        somebody.say()
        
        //tarly出场
        var tarly = NightWatcher(name: "Tarly")
        tarly.say()
        
        /*
        我是守夜人 我的剑长0.5米 由普通钢铸造而成
        我是Tarly 我的剑长1.0米 由龙晶铸造

        注意:
        在扩展的便捷构造器内可以自由使用其原有的指定构造器和便捷构造器.
        扩展的结构体Sword的构造器.此处没有什么指定构造器和便捷构造器的说法,并且依然可以调用其成员构造器和默认构造器.
        */
} 

下标(subscript)

extension Int {
    subscript(var digitIndex: Int) -> Int {
        var decimalBase = 1
        while digitIndex > 0 {
            decimalBase *= 10
            --digitIndex
        }
        return (self / decimalBase) % 10
    }
}
//扩展可以向一个已有类型添加新下标。这个例子向Swift内建类型Int添加了一个整型下标。该下标[n]返回十进制数字从右向左数的第n个数字.
func testThree(){
        
        print(746381295[0])// returns 5
        print(746381295[1])// returns 9
        print(746381295[2])// returns 2
        print(746381295[8])// returns 7
        
        //如果该Int值没有足够的位数,即下标越界,那么上述实现的下标会返回0,因为它会在数字左边自动补0:
  
         print(746381295[9])//returns 0, 即等同于:
         print(0746381295[9])//returns 0
        
    
 }

看一个小例子

import UIKit

//创建一个Person
class Person{
    
    var firstName:String,lastName:String
    var age = 0
    var fullName:String{
        get{
            return firstName + lastName
        }
    }
    
    init(firstName:String,lastName:String){
        self.firstName = firstName
        self.lastName = lastName
        
    }
    
    func showMessage(){
        print("name:\(fullName),age:\(age)")
    }
}

//对Person类进行扩展
extension Person{
    
    //只能扩展便利构造方法,不能扩展指定构造方法.
    convenience init(){
        self.init(firstName:"",lastName:"")
    }
    
    //只能扩展计算属性,无法扩展存储属性.对于属性不理解可以参考http://swiftcn.io/doc/chapter2/10_Properties.html
    var personInfo:String{
        return "firstName=\(firstName),lastName=\(lastName),age=\(age)"
    }
    
    //扩展实例方法
    func showHello(){
        print("Nice to meet you!")
    }
    
    //嵌套类型
    enum SkinColor{
         case Yellow,White,Black
    }
    
    //扩展类型方法
    static func skins() -> [SkinColor]{
        return [.Yellow,.White,.Black]
    }
}

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let p = Person()
        p.firstName = "ShiHua"
        p.lastName = "Long"
        p.age = 24
        
        print(p.personInfo)
        p.showHello()
        print(Person.skins())
        
    }
    
}


你可能感兴趣的:(Swift 扩展(extension))