Swift学习之路-Extension

本文首发地址
请在阅读本文章时,顺手将文中的示例代码在playground中敲一遍,这样能加深理解!!!
阅读该文章大约需要:15分钟
读完之后你能获得:
1、Extension是什么
2、它能做什么

本文全部内容基于Swift版本:3.0.1

Extension的基本语法

extension SomeType {
    // new functionality to add to SomeType goes here
}

Tip:扩展可以为一个类型添加新的功能,但是不能重写已有的功能。

struct Student {
    var name = ""
    var age = 1
    func print() {
        
    }
}

extension Student {
    //改行会报错`invalid redeclaration print()`重复声明print(),重写变量也是不行的。
    func print() {
    }
}

Swift中的Extension可以做什么

我们想知道Extension在Swift中能做些什么,最直接的方法就是查看Swift的官方文档了。下面是文档中指出Extension能做的六个方面。

  • 添加计算型实例属性和计算型类型属性
  • 定义实例方法和类型方法
  • 提供新的构造器
  • 定义下标
  • 定义和使用新的嵌套类型
  • 使已存在的类型遵守某个协议

看完上面Extension能做的六个方面,我们来逐条解释说明一下:

添加计算型实例属性和计算型类型属性

首先我们要了解什么是计算型属性,计算型属性(computed property)不直接存储值,而是提供一个getter和一个可选的setter,来间接获取和设置其他属性或变量的值。关于更多的计算型属性的内容请自行查看官方文档,在此不再赘述。那么我们什么场景可以用到这个功能呢?举一个最常见的例子,当你想访问某个view的width的时候,通常情况下你会这么写:

view.frame.size.width

但是这样写很长很不方便,作为一个懒惰的程序员,这时候你就要想我能不能缩短访问该属性的代码。不要犹豫了骚年,这时候你只需要写一个UIView的Extension就可以达到你的目的。

extension UIView {
    var x: CGFloat { return self.frame.origin.x }
    var y: CGFloat { return self.frame.origin.y }
    var width: CGFloat { return self.frame.size.width }
    var height: CGFloat { return self.frame.size.height }
}

这样你就可以通过来访问该属性。怎么样,有没有感受到Extension的便利之处。

view.width

定义实例方法和类型方法

在你辛辛苦苦写完一个Student类后,万恶的产品过来告诉你需求改了,这时虽然你心中有一万只草泥马在奔腾,但是为了心中那份神圣的程序员的责任感(当然还有糊口的工资),你还是要修改代码。如果你想在不改变原始类的基础上添加功能,那你可以给Student类添加Extension来解决问题。

Tip:这里值得注意的一点是在Swift中,Extension可以给类和类型添加,比如你也可以给一个struct添加Extension,而在Objective-C中,你只能给类添加Extension。

class Student {
    var name = ""
    var age = 1
}

extension Student {
    func printCurrentStudentName() {
        print(self.name)
    }
}

var jack = Student()
jack.name = "jack"
jack.printCurrentStudentName()

提供新的构造器(Initializers)

最常见的Rect通常由originsize来构造初始化,但是如果在你写完Rect的定义后,你偏偏想要通过center和size来确定Rect(作为一个程序员就要有一种作死的精神),那你就要用Extension来给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()
}

let defaultRect = Rect()
let memberwiseRect = Rect(origin: Point(x: 2.0, y: 2.0),
                          size: Size(width: 5.0, height: 5.0))

通过Extension来给Rect添加一个新的构造器。

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)
    }
}

这样你就可以通过新的构造器来初始化Rect。

let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
                      size: Size(width: 3.0, height: 3.0))
// centerRect's origin is (2.5, 2.5) and its size is (3.0, 3.0)

定义下标

通过Swift中的Extension,你可以给已知类型添加下标。例如下面的例子就是给Int类型添加一个下标,该下标表示十进制数从右向左的第n个数字。

本例子来源官方文档

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

定义和使用新的嵌套类型(nest type)

Extensions可以给已知的类、结构体、枚举添加嵌套类型。下面的例子是给Int类型添加一个判断正负数的Extension,该Extension嵌套一个枚举。

本例子来源官方文档

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])
// Prints "+ + - 0 - 0 + "

使已存在的类型遵守某个协议

编写使该类型遵守某个协议的Extension的语法如下:

extension SomeType: SomeProtocol, AnotherProtocol {
    // implementation of protocol requirements goes here
}

示例代码:

protocol StudentProtocol {
    var address: String { get }
}

struct Student {
    var name = ""
    var age = 1
    
}

extension Student: StudentProtocol {
    var address: String {
        return "address"
    }
}

var jack = Student()
jack.address
//输出 address

若添加Extension的类型已经实现协议中的内容,你可以写一个空的Extension来遵守协议:

protocol StudentProtocol {
    var address: String { get }
}

struct Student {
    var address: String {
        return "address"
    }
    var name = ""
    var age = 1
}

extension Student: StudentProtocol {}

var jack = Student()
jack.address
//输出 address

总结

  • Extension可以为一个已有的类、结构体、枚举类型或者协议类型添加新功能。
  • 可以在没有权限获取原始源代码的情况下扩展类型的内容
  • Extendion和Objective-C中的Category类似。(OC中的Category有名字,Swift中的扩展没有名字)

下篇预告:Swift-Protocol

若本文有何错误或者不当之处,还望不吝赐教。谢谢!

Swift-Extension的官方文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容