本文首發於我的博客html
協議,有關開發經驗的應該都不陌生,不少語言中都有協議,可是相對來講,Swift中的協議更增強大,靈活。git
//協議
protocol Drawable {
//方法
func draw()
//可讀可寫屬性
var x: Int { get set }
//只讀屬性
var y: Int { get }
// 下標
subscript(index: Int) -> Int { get set }
}
複製代碼
類TestClass
準守多個協議github
protocol Test1 { }
protocol Test2 { }
protocol Test3 { }
class TestClass : Test1, Test2, Test3 { }
複製代碼
eg:有協議Drawable
,裏面有方法draw
,以及可讀可寫屬性x
,只讀屬性y
,下標。其中屬性必須用var
關鍵字spring
//協議
protocol Drawable {
func draw() //方法
var x: Int { get set } //可讀可寫 屬性用var
var y: Int { get } //只讀 屬性用var
subscript(index: Int) -> Int { get set } //下標
}
複製代碼
當實現的時候,有以下的方式,編程
class Person : Drawable {
var x: Int = 0 //用var的存儲屬性
let y: Int = 0 //let實現只讀屬性
func draw() {
print("Person draw")
}
subscript(index: Int) -> Int {
set { }
get { index }
}
}
複製代碼
固然了。也能夠寫成以下這種swift
class Person : Drawable {
var x: Int { //用計算屬性
get { 0 }
set { }
}
var y: Int { 0 } //var實現只讀屬性
func draw() { print("Person draw") }
subscript(index: Int) -> Int {
set { }
get { index }
}
}
複製代碼
protocol Drawable {
//這裏必須用static
static func draw()
}
class Person1 : Drawable {
//這裏能夠用class
class func draw() {
print("Person1 draw")
}
}
class Person2 : Drawable {
//這裏也能夠用static
static func draw() {
print("Person2 draw")
}
}
複製代碼
關於mutating
能夠參考Swift之方法數組
eg:bash
protocol Drawable {
mutating func draw()
}
class Size : Drawable {
var width: Int = 0
func draw() {
width = 10
}
}
struct Point : Drawable {
var x: Int = 0
mutating func draw() {
x = 10
}
}
複製代碼
能夠這麼理解,若是定義的類,有子類,那麼子類必須準守初始化器init,因此加上關鍵字required
,可是,若是一個被final
修飾的類。就不用加上required
.由於被final
修飾的類不能被其餘類繼承。app
關於final
可參考Swift之繼承ide
eg: 有協議Drawable
,裏面定義了初始化器init
,類Point遵照這個協議,因此在init 前面加了關鍵字 required
,這樣,繼承類Point的子類都要實現這個方法,可是類Size沒子類。由於加了關鍵字final
,這個類不能被繼承。因此init
前面不用加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) { }
}
複製代碼
eg:
protocol Livable {
init(age: Int)
}
class Person {
init(age: Int) { }
}
class Student : Person, Livable {
required override init(age: Int) {
super.init(age: age)
}
}
複製代碼
eg:
//協議
protocol Livable {
init()
init?(age: Int)
init!(no: Int)
}
//類
class Person : Livable {
//下面兩種均可以實現init()
required init() { }
// required init!() { }
//下面3種均可以實現init?(age: Int)
required init?(age: Int) { }
// required init!(age: Int) { }
// required init(age: Int) { }
//下面3種均可以實現 init!(no: Int)
required init!(no: Int) { }
// required init?(no: Int) { }
// required init(no: Int) { }
}
複製代碼
eg
// 協議Runnable
protocol Runnable {
func run()
}
// 協議Livable 繼承協議 Runnable
protocol Livable : Runnable {
func breath()
}
class Person : Livable {
func breath() { }
func run() { }
}
複製代碼
eg: 兩個協議Livable
和Runnable
,類Person
protocol Livable { } n
protocol Runnable { }
class Person { }
複製代碼
下面定義了fn0,接收參數必須是Person或者其子類的實例。fn1接收參數必須遵照Livable協議的實例,其餘的能夠自行看代碼
// 接收Person或者其子類的實例
func fn0(obj: Person) { }
// 接收遵照Livable協議的實例
func fn1(obj: Livable) { }
// 接收同時遵照Livable、Runnable協議的實例
func fn2(obj: Livable & Runnable) { }
// 接收同時遵照Livable、Runnable協議、而且是Person或者其子類的實例
func fn3(obj: Person & Livable & Runnable) { }
typealias RealPerson = Person & Livable & Runnable
// 接收同時遵照Livable、Runnable協議、而且是Person或者其子類的實例
func fn4(obj: RealPerson) { }
複製代碼
// 枚舉Season遵照協議CaseIterable
enum Season : CaseIterable {
case spring, summer, autumn, winter
}
// 取出全部的case
let seasons = Season.allCases
print(seasons.count) // 4
// 能夠遍歷
for season in seasons {
print(season)
} // spring summer autumn winter
複製代碼
eg: Person
類遵照了CustomStringConvertible
協議,能夠再內部自定義打印description
。
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
複製代碼
eg: stu屬於Any類型,能夠賦值爲字符串或者對象等
var stu: Any = 10
stu = "Jack"
stu = Student()
複製代碼
eg: 建立1個能存聽任意類型的數組
// 建立1個能存聽任意類型的數組
// 第一種寫法
// var data = Array<Any>()
// 第二種寫法
var data = [Any]()
data.append(1)
data.append(3.14)
data.append(Student())
data.append("Jack")
data.append({ 10 })
複製代碼
eg: 定義協議Runnable
,類Person
和類Student
protocol Runnable { func run() }
class Person { }
class Student : Person, Runnable {
func run() {
print("Student run")
}
func study() {
print("Student study")
}
}
複製代碼
使用is 的時候
var stu: Any = 10
print(stu is Int) // true
stu = "Jack"
print(stu is String) // true
stu = Student()
print(stu is Person) // true
print(stu is Student) // true
print(stu is Runnable) // t
複製代碼
使用as 的時候,若是轉換失敗,後面都不執行。轉換成功,後面才繼續執行
var stu: Any = 10
(stu as? Student)?.study() // 沒有調用study
stu = Student()
(stu as? Student)?.study() // Student study
(stu as! Student).study() // Student study
(stu as? Runnable)?.run() // Student run
複製代碼
// 定義類Person
class Person { }
// 定義類Student 繼承 Person
class Student : Person { }
//perType類型是 Person.Type
var perType: Person.Type = Person.self
//stuType類型是 Student.Type
var stuType: Student.Type = Student.self
// Student.self能夠賦值給perType
perType = Student.self
// anyType能夠是任何類型
var anyType: AnyObject.Type = Person.self
anyType = Student.self
public typealias AnyClass = AnyObject.Type
//anyType2能夠是任何類型
var anyType2: AnyClass = Person.self
anyType2 = Student.self
複製代碼
eg:Cat
類,Dog
類,Pig
類,都繼承自Animal
類,咱們想同時去初始化,可以使用下面的代碼
class Animal { required init() { } }
class Cat : Animal { }
class Dog : Animal { }
class Pig : Animal { }
func create(_ clses: [Animal.Type]) -> [Animal] {
var arr = [Animal]()
for cls in clses {
// 根據元類型初始化
arr.append(cls.init())
}
return arr
}
// 這裏傳入Cat,Dog,Pig進行初始化
print(create([Cat.self, Dog.self, Pig.self]))
複製代碼
注意上面的required不能省略
實際上,真的如此麼,真的不繼承任何類麼?
class Person {
var age: Int = 0
}
class Student : Person {
var no: Int = 0
}
print(class_getInstanceSize(Student.self)) // 32
print(class_getSuperclass(Student.self)!) // Person
print(class_getSuperclass(Person.self)!) // Swift._SwiftObject
複製代碼
有點相似OC中的instanType的感受。eg:
protocol Runnable {
func test() -> Self
}
class Person : Runnable {
required init() { }
func test() -> Self { type(of: self).init() }
}
class Student : Person { }
複製代碼
調用時候
var p = Person()
// 輸出Person
print(p.test())
var stu = Student()
// 輸出Student
print(stu.test())
複製代碼
參考資料: