Cowboy Tech

Swift中的扩展和协议

扩展

特点

  1. Swift的扩展与OC的Category类似,只是swift中的扩展没有名字.
  2. 扩展并不是派生子类,因此不支持重写
  3. 可以使一个已有类型符合一个或者多个协议

语法定义

修饰符可以省略,或者是private,internal,public其中之一,类型可以是枚举,结构体和类其中之一

1
2
3
[修饰符]extension已有类型{
//添加新功能
}

1
2
3
[修饰符]extension已有类型:协议1,协议2{
//添加新功能
}

添加属性

使用扩展可以添加3种属性:类型存储属性,实例计算属性,类型计算属性,就是不能添加实例存储属性

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
40
41
42
43
extension String {
static var data:[String:Any] = [:]
var length:Int{
get{
return self.characters.count
}
set{
let originLength = self.characters.count
//如果新设置的长度大于字符串原有长度,在字符串后面添加空字符
if newValue > originLength {
for _ in 1...newValue - originLength {
self += " "
}
}
//如果新设置的长度小于字符串原有长度,将后面多余的字符截断
else if newValue < originLength {
var tmp = ""
var count = 0
for ch in self.characters {
tmp = "\(tmp)\(ch)"
count++
//如果已经拼接了newValue个字符,跳出循环
if count == newValue {
break
}
}
self = tmp
}
}
}
}
String.data["swift"] = 89
String.data["OC"] = 92
print(String.data)
var s = "jike.org"
//通过length输出字符串的长度
print(s.length)
//通过设置length属性,截断String后面多出来的字符
//s.length = 5
//print(s)
//通过设置length属性,在string后面补充空格
s.length = 10
print(s)

添加方法

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
extension String {
//添加一个新方法,用于获取当前字符串中指定范围的子串
func substringFromStart(start:Int, toEnd:Int) ->String{
var count = 0
var tmp = ""
for ch in self.characters {
if count >= start {
tmp = "\(tmp)\(ch)"
}
if count >= toEnd - 1 {
break
}
count++
}
return tmp
}
//定义一个类方法
static func valueOf(value:Bool) ->String{
return "\(value)"
}
}
var str = "jike.isagoodstudycenter"
//截取原字符串中从索引5开始,到索引10之间的子串
var subStr = str.substringFromStart(5, toEnd: 10)
print(subStr)
print(String.valueOf(true))
print(String.valueOf(false))

添加可变方法

类不可以定义可变方法,不能通过扩展来为类添加可变方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
extension Array {
//定义一个方法,用于计算数组的交集
mutating func retainAll(array:[Element],compartor:(Element,Element)->Bool){
var tmp = [Element]()
//遍历当前数组中所有元素
for ele in self {
//遍历第二个数组的所有元素
for target in array {
//如果两个元素通过compartor比较返回true
if compartor(ele,target){
tmp.append(ele)
break
}
}
}
self = tmp
}
}
var books = ["iOS","Android","Swift","Java","Ruby"]
books.retainAll(["Android","iOS","C"]){
return $0 == $1
}
print(books)

添加下标

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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
extension String {
subscript(idx:Int)->String{
get{
//如果下标位于字符串长度之内
if idx > -1 && idx < self.characters.count {
var count = 0
var result = ""
//通过遍历搜索字符串内指定索引处的字符
for ch in self.characters{
if count == idx {
//将找到的字符转换为字符串
result = "\(ch)"
}
count++
}
return result
}
//如果下标没有位于字符串长度之内,返回空字符串
else{
return""
}
}
set{
var result = ""
var count = 0
for ch in self.characters{
if count == idx{
result += newValue
}
else{
result += "\(ch)"
}
count++
}
self = result
}
}
//定义只读下标
subscript(start:Int,end:Int)->String{
//如果start,end都位于字符串长度之内,且start小于end
if start > -1 && start < self.characters.count
&& end > -1 && end <= self.characters.count
&& start < end {
var result = ""
var count = 0
for ch in self.characters {
if count >= start && count < end{
result.append(ch)
}
count++
}
return result
}
//如果给定的下标不符合要求,程序直接返回空字符串
else {
return ""
}
}
}
//定义一个字符串
var s = "jike is a excellent training center"
//通过下标访问索引为5的字符
print(s[5])
//通过下标改变字符串指定索引处的字符
s[0] = "J"
s[2] = "K"
print(s)
//通过带两个Int参数的下标来获取字符串中间范围的子串
print(s[2,6])

添加构造器

  1. 没有构造器,系统会提供默认的,
  2. 已经定义了,系统就不会提供构造器
  3. 想要他们并存,就需要扩展,通过扩展添加的构造器,不会影响原有的构造器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//定义一个结构体
struct SomeStruct{
var name:String
var count:Int
}
//使用扩展来添加构造器
extension SomeStruct{
init(name:String){
self.name = name
self.count = 0
}
init(count:Int){
self.count = count
self.name = ""
}
}
//下面使用了SomeStruct的3个构造器
var sc1 = SomeStruct(name: "jike", count: 5)
var sc2 = SomeStruct(name: "crazyjike")
var sc3 = SomeStruct(count: 20)

添加嵌套类型

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
extension String {
//定义一个嵌套枚举
enum Suit:String{
case Diamond = "A"
case Club = "B"
case Heart = "C"
case Spade = "D"
}
//通过扩展为String增加一个类型方法,用于判断指定字符串属于哪种花色
static func judgeSuit(s:String)->Suit?{
switch(s){
case "A":
return .Diamond
case "B":
return .Club
case "C":
return .Heart
case "D":
return .Spade
default:
return nil
}
}
}
//使用Strig包含的嵌套枚举
var s1:String.Suit? = String.judgeSuit("C")
print(s1)
var s2:String.Suit? = String.judgeSuit("j")
print(s2)

Protocol - 规范和实现的分离 & 松耦合的设计

一个协议可以有多个直接父协议,但协议只能继承协议,不能继承类

[修饰符]protocol协议名:父协议1,父协议2,...{
//协议内容
}

协议定义了一种规范,不提供任何实现

protocol Souschef {
    func chop(vegetable: String) -> String
    func rinse(vegetable: String) -> String
}

协议的实现

class Roommate: Souschef, Equatable {
    var hungry = true
    var name: String

    init(hungry: Bool, name: String) {
        self.hungry = hungry
        self.name = name
    }

    func chop(vegetable: String) -> String {
        return "She's choppin' \(vegetable)!"
    }

    func rinse(vegetable: String) -> String {
        return "The \(vegetable) is so fresh and so clean"
    }
}

安装一个适用于对象比较的协议

func ==(lhs: Roommate, rhs: Roommate) -> Bool {
    return lhs.name == rhs.name && lhs.hungry == rhs.hungry
}

var roomie = Roommate(hungry: true, name: "Jennifer")
var theBestRoomie = Roommate(hungry: true, name: "Jennifer")

roomie == theBestRoomie

A protocol is also a type

class DinnerCrew {
    var members: [Souschef]

    init(members: [Souschef]) {
        self.members = members
    }
}

class RandomPasserby: Souschef {
    var name: String

    init(name: String){
        self.name = name
    }

    func chop(vegetable: String) -> String {
        return "She's choppin' \(vegetable)!"
    }

    func rinse(vegetable: String) -> String {
        return "The \(vegetable) is so fresh and so clean"
    }
}

var newFriend = RandomPasserby(name: "Dave")
var motleyDinnerCrew = DinnerCrew(members:[newFriend, roomie])

协议语法和属性要求

1
class var 属性名:类型{get set}
  1. class可有可无。如果有class关键字,说明为类型属性,否则为实例属性。不可以使用static代替class
  2. get和set部分:只需要写get,set即可,无须提供实现,set可有可无
  3. 协议多继承,弥补了类单继承的不足
  4. 协议中使用class关键字定义类型属性,但值类型中依然使用static定义类型属性
    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
    40
    41
    protocol Strokable{
    var strokeWidth:Double {get set}
    }
    protocol Fullable{
    var fullColor:Color? {get set}
    }
    //定义一个枚举作为协议属性的类型
    enum Color {
    case Red,Green,Blue,Yellow,Cyan
    }
    protocol HasArea:Fullable,Strokable {
    var area:Double{get}
    }
    protocol Mathable{
    //这里怎么用static? 和说明上不一样哦
    static var pi: Double {get}
    static var e: Double {get}
    }
    //让Rect实现2个协议
    struct Rect:HasArea,Mathable{
    var width:Double
    var height:Double
    init(width:Double,height:Double){
    self.width = width
    self.height = height
    }
    //使用存储属性实现Fullable协议的fullColor属性
    var fullColor:Color?
    //使用存储属性实现Strokable协议的strokeWidth属性
    var strokeWidth:Double = 0.0
    //使用存储属性实现HASAREA协议要求的area属性
    var area: Double{
    get{
    return width * height
    }
    }
    //通过存储属性实现Mathable协议要求的两个类型属性
    //虽然协议中使用class关键字定义类型属性,但值类型中依然使用static定义类型属性
    static var pi:Double = 3.14159
    static var e:Double = 2.71626
    }