Swift笔记 - 08.可选链、协议
Swift笔记 - 08.可选链、协议
可选链
class Car { var price = 0 }
class Dog { var weight = 0 }
class Person {
var name: String
var dog: Dog = Dog()
var car: Car? = Car()
func age() -> Int { 18 }
func eat() { print ("Person eat") }
subscript (index: Int) -> Int { index }
}
var person: Person? = Person()
var agel = person!.age() // Int
var age2 = person?.age() // Int?
var name = person?.name // String?
var index = person? [6] // Int?
func getName()-> String{ "jack" }
//如果person是nil,不会调用getName()
person?.name = getName()
- 如果可选项为nil,调用方法、下标、属性失败,结果为nil
- 如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
- 如果结果本来就是可选项,不会进行再次包装
if let _ = person?.eat() { // ()?
print("eat调用成功")
} else {
print("eat调用失败")
}
var dog = person?.dog // Dog?
var weight = person?.dog.weight // Int?
var price = person?.car?.price // Int?
- 多个?可以链接在一起
- 如果链中任何一个节点是nil,那么整个链就会调用失败
var scores = ["Jack": [86, 82, 84], "Rose": [79, 94, 81]]
scores ["Jack"]?[0] = 100
scores ["Rose"]? [2] += 10
scores ["Kate"]?[0] = 88
var num1: Int? = 5
num1? = 10 // Optional(10)
var num2: Int? = nil
num2? = 10 // nil
var dict: [String : (Int, Int) -> Int] = [
" sum" : (+),
"differencell" : (-)
]
var result = dict["sum"]? (10, 20) // Optional (30), Int?
协议(Protocol)
- 协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)
protocol Drawable {
func draw()
var x: Int { get set }
var y: Int { get }
subscript(index :Int)->Int { get set }
}
protocol Test1 { }
protocol Test2 { }
protocol Test3 { }
class TestClass : Test1, Test2, Test3 { }
- 协议中定义方法时不能有默认参数值
- 默认情况下,协议中定义的内容必须全部都实现
协议中的属性
- 协议中定义属性时必须用
var
关键字 - 实现协议时的属性权限要不小于协议中定义的属性权限
- 协议定义
get
、set
,用var
存储属性或get
、set
计算属性去实现 - 协议定义
get
,用任何属性都可以实现
protocol Drawable {
func draw()
var x: Int { get set }
var y: Int { get }
subscript (index: Int) -> Int { get set }
}
class Person : Drawable {
var x: Int = 0
let y: Int = 0
func draw() {
print ("Person draw")
}
subscript(index: Int) -> Int {
set { }
get { index }
}
}
class Person : Drawable {
var x: Int
{
get {0}
set { }
}
var y: Int { 0 }
func draw() { print ("Person draw") }
subscript(index: Int) -> Int {
set { }
get { index }
}
}
- 为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标
protocol Drawable {
static func draw()
}
class Person: Drawable {
class func draw() {
print("Person1 draw")
}
}
class Person2: Drawable {
static func draw() {
print("Person2 draw")
}
}
- 只有将协议中的实例方法标记为
mutating
- 才允许结构体、枚举的具体实现修改自身内存
- 类在实现方法时不用加
mutating
,枚举、结构体才需要加mutating
protocol Drawable {
mutating func draw()
}
class Size: Drawable {
var width: Int = 0
func draw() {
width = 10
}
}
struct Point: Drawable {
var x: Int = 10
mutating func draw() {
x = 10
}
}
- 协议中还可以定义初始化器
init
- 非
final
类实现时必须加上required
protocol Drawable {
init(x: Int, y: Int)
}
class Point : Drawable {
required init(x: Int, y: Int) { }
}
final class Size : Drawable {
init(x: Int, y: Int) { }
}
- 如果从协议实现的初始化器,刚好是重写了父类的指定初始化器
- 那么这个初始化必须同时加
required.override
protocol Livable {
init(age: Int)
}
class Person {
init(age: Int) { }
}
class Student : Person, Livable {
required override init(age: Int) {
super.init(age: age)
}
}
- 协议中定义的
init?
、init!
,可以用init
、init?
、init!
去实现 - 协议中定义的
init
,可以用init
、init!
去实现
protocol Livable {
init()
init?(age: Int)
init!(no: Int)
}
class Person : Livable {
required init() { }
// required init! 0 { }
required init? (age: Int) { }
// required init! (age: Int) {}
// required init(age: Int) { }
required init! (no: Int) { }
// required init?(no: Int) { }
// required init(no: Int) { }
}
协议的继承与组合
- 一个协议可以继承其他协议
protocol Runnable {
func run()
}
protocol Livable : Runnable {
func breath()
}
class Person: Livable {
func breath() { }
func run() { }
}
- 协议组合,可以包含1个类类型(最多1个)
protocol Livable { }
protocol Runnable { }
class Person { }
//接收Person或者其子类的实例
func fn0(obi: Person){}
//接收遵守Livable协议的实例
func fn1(obj: Livable) { }
//接收同时遵守Livable、Runnable协议的实例
func fn2(obi: Livable & Runnable){}
//接收同时遵守Livable、Runnable协议、并且是Person或者其子类的实例
func fn3(obj: Person & Livable & Runnable) {}
typealias RealPerson = Person & Livable & Runnable
//接收同时遵守Livable、Runnable协议、并且是Person或者其子类的实例
func fn4(obj: RealPerson) { }
CaseIterable协议
- 让枚举遵守CaseIterable协议,可以实现遍历枚举值
enum Season : CaseIterable {
case spring, summer, autumn, winter
}
let seasons = Season.allCases
print(seasons.count) // 4
for season in seasons {
print (season)
} // spring summer autumn winter
CustomStringConvertible协议
- 遵守Customstringconvertible协议,可以自定义实例的打印字符串
class Person: CustomStringConvertible {
var age: Int
var name: String
init(age: Int, name: String) {
self.age = age
self.name = name
}
var description: String {
"age=\(age), name=\(name)"
}
}
var p = Person(age: 10, name: "Jack")
print(p) // age=10, name=Jack