Swift中可以对类,结构体,协议,枚举进行拓展添加新的功能
考虑到本篇博文中的篇幅,关于枚举的拓展将在下一篇介绍ps:
基于Swift 5
Swift 中的扩展可以:
- 一、添加计算型属性和计算型静态属性
- 二、定义实例方法和类型方法
- 三、提供新的构造器
- 四、定义下标
- 五、定义和使用新的嵌套类型
- 六、使一个已有类型符合某个协议
一、添加计算型属性、计算型静态属性、“存储属性”
调用示例1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40class Animal:NSObject {
var age:Int?
}
private var animalName:String = ""
extension Animal {
//1添加静态计算属性
static var c:Int{
get {
print("get c")
return 3
}
set{
print("set c:\(newValue)")
}
}
//2添加计算属性
var isAdult:Bool{
get{
return self.age ?? 0 > 2
}
set{
if newValue {
self.age = 2
}else{
self.age = 0
}
}
}
//3使用AssociatedObject添加存储属性
var name:String {
get{
return objc_getAssociatedObject(self, &animalName) as! String
}
set{
objc_setAssociatedObject(self, &animalName, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
}1
2
3
4
5
6
7
8
9
10let animal = Animal()
animal.age = 3
print("\(animal.age)")//Optional(3)
animal.name = "AA"
animal.isAdult = true
print("-----")
print("\(animal.age)")//Optional(2)
print("\(animal.name)")//AA
Animal.c = 6
print(Animal.c)
1,这里需要解释一下官方文档中虽然介绍extension
不能添加存储属性,但是依旧可以利用AssociatedObject
来达到添加存储属性的效果
2,在类和结构体中添加计算属性,“存储属性”可以按照以上方式,但是在protocol
中又会是何种情况呢?我们知道protocol
中可以定义属性和方法,而遵循该protocol
的类或结构体就必须实现其中的方法,添加其中的属性(Optional除外)。如果在定义protocol
时并没有申明子类必须添加某个属性,而你通过拓展添加了一个存储属性,那你之前遵循过此协议的子类岂不是都不能编译通过了。因此在拓展协议时只能添加Optional
属性。在协议中添加
optional
属性1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40protocol P{
var name:String{ get set}
}
extension P{
//添加静态计算属性
static var c:Int{
get {
print("get c")
return 3
}
set{
print("set c:\(newValue)")
}
}
//添加计算属性
var temp:Bool{
get{
return true
}
set{
print("set temp:\(newValue)")
}
}
//使用AssociatedObject添加存储属性
var words:String? {
get{
return objc_getAssociatedObject(self, &animalName) as? String
}
set{
objc_setAssociatedObject(self, &animalName, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
}
}
class B : P{
var name: String = ""
}
二、定义实例方法和类型方法
1 | extension String { |
1,在结构体和类中添加拓展方法应该是日常开发中最为常见的
2,在拓展类时添加实例方法既可以用class
修饰也可以使用static
修饰,而在结构体和协议中只能使用static
修饰,因为Class methods are only allowed within classes
三、提供新的构造器
1,给结构体添加新的构造器
1 | struct H{ |
从上图的代码提示中可以看到struct
H
在初始化时有系统默认生成的一个无参构造函数和一个带有所有属性的构造函数,以及我们在extension
中添加的两个构造函数
2,给类添加新的构造器
1 | extension UIColor{ |
与struct
不同的是在拓展类时只能添加便利构造器
四、定义下标
1 | extension String |
类同理
1 | class People{ |
ps:
对于类拓展下标的功能写完我真的是给Swift
跪了,可以自定义参数,自定义返回值。上面拓展String
的下标访问还可以理解,对于给类添加下标访问方法目前我还没有发现有什么妙用,如果有什么好案例还望不吝赐教。
五、定义嵌套类型
1 | class People{ |
六、使一个已有类型符合某个协议
1 | extension MAOrderListSecondViewController :UITableViewDelegate,UITableViewDataSource{ |
在开发中我经常将某个类需要遵循的协议使用extension
分割开来以提高代码的可读性
七、拓展协议添加where
从句
1 | protocol MAViewProtocol { |
上面的代码段中color.getString()
是无法通过编译的。首先我在MAViewProtocol
的拓展中添加了getString()
方法虽然MATestColor
和MATestView
都遵循了MAViewProtocol
,但是我在拓展时添加了where
从句where Self:UIView
。意思为只有是UIView
的子类才能使用该拓展中的方法,而MATestColor
继承自UIColor
因此无法调用getString()
方法
八、通过拓展协议实现命名空间
从事iOS开发的同学应该不会对Kingfisher
中的kf
,RxSwift
中rx
感到陌生
1 | public struct Reactive<Base> { |
这段代码是从RxSwift
框架中截取出来,目前对于我来说只是知其然不知其所以然,后续再慢慢深究吧。
参考文献
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html#//apple_ref/doc/uid/TP40014097-CH24-ID152
https://www.runoob.com/swift/swift-extensions.html