协议
-
协议的特点
1. 协议可以定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议用逗号分割)
2. 协议中定义方法时不能有默认的参数
3. 默认情况下,协议中的所有内容必须全部都实现 -
协议中的属性
1. 协议中定义的属性必须用var
关键字
2. 实现协议的属性权限要不小于协议中定义的属性权限
3. 协议定义get/set
,用var
存储属性或get/set
计算属性去实现
4. 协议定义get,用任何属性都可以实现
class Person: Drawable {
required init(x: Int, y: Int) {
self.x = x
self.y = y
}
var x: Int = 0
var y: Int = 0
func draw() {
print("person draw")
}
subscript(index: Int) -> Int {
get {index}
set {}
}
static func cDraw() {
print("协议中定义的类型方法")
}
}
-
static/class
为了保证通用,协议中必须用static
定义类型方法、类型属性、类型下标
-
static
是通用的,class只能在类中声明类型方法,为了保证通用,所以协议声明类型方法的时候需要使用static
- 类
class
在实现协议的类型方法的时候,可以更改类型方法的修饰关键字为class
,这样能够保证当前的类型方法能够被子类继承
-
class Person2: Drawable {
func draw() {}
var x: Int = 0
var y: Int = 0
required init(x: Int, y: Int) {
self.x = x
self.y = y
}
subscript(index: Int) -> Int {
get {
index
}
set {}
}
//改成class之后能够被子类继承
class func cDraw() {
print("我改了协议中定义的类型方法为可继承")
}
}
class Son: Person2 {
override class func cDraw() {
super.cDraw()
print("子类重写父类方法")
}
}
-
协议中的
mutating
1. 只有将协议中的实例方法标记为mutating
才允许结构体、枚举的具体实现修改自身的内存
2. 类在实现方法时不用加mutating
,枚举、结构体才需要加mutating
-
协议中的init
1. 协议中还可以定义初始化器init
2. 非final
类实现时必须加上required
struct Point: Drawable {
mutating func draw() {
self.x = 20
print("结构体来实现画画")
}
var x: Int = 0
var y: Int = 0
subscript(index: Int) -> Int {
get {index}
set {}
}
static func cDraw() {
print("结构体类型方法")
}
}
class Person3 {
var x: Int = 0
var y: Int = 0
required init(x: Int, y: Int) {
self.x = x
self.y = y
print("来自 Person3")
}
}
- 同时实现协议中的
init
与 重写父类的init
问题
这个初始化必须同时加上required
、override
关键字修饰
class SonTwo: Person3, Drawable {
func draw() {}
subscript(index: Int) -> Int {
get {index}
set {}
}
required init(x: Int, y: Int) {
super.init(x: x, y: y)
}
static func cDraw() {}
}
- 协议中
init/init?/init!
- 协议中定义的
init?/init!
可以用init/init?/init!
去实现 - 协议中定义的
init
,可以用init/init!
来实现
- 协议中定义的
class Person4: Livable {
// required init() {}
required init!(){}
// required init?(age: Int) {}
// required init!(age: Int) {}
required init(age: Int) {}
// required init!(no: Int) {}
required init?(no: Int) {}
}
- 协议的继承与组合
- 一个协议可以继承其他协议
- 可以通过
&
组合多个类型的协议 - 协议组合,可以包含1个类类型(最多一个)
- 可以使用扩展
extension
来扩展协议的默认实现
protocol Drawable {
mutating func draw()
var x: Int{get set}
var y: Int{get}
subscript(index: Int) -> Int {set get}
init(x: Int, y: Int)
static func cDraw()
}
protocol Livable {
init()
init?(age: Int)
init!(no: Int)
}
extension Drawable {
mutating func draw(){
print("扩展默认实现draw方法")
}
subscript(index: Int) -> Int {
set { }
get { index }
}
static func cDraw(){
print("扩展默认实现cDraw方法")
}
}
protocol InterProtocol: Drawable {
func endDraw()
}
class protocolUseDemo {
//接收Person及其子类的实例
func fn0(obj: Person){}
//接收遵守Livable协议的实例
func fn1(obj: Livable) {}
//接收同时遵守Livable、InterProtocol 协议的实例
func fn2(obj: Livable & InterProtocol) {}
//接收同时遵守Livable、InterProtocol、Drawable 协议的实例
func fn3(obj: Livable & InterProtocol & Drawable) {}
}
- 常见的系统自带的协议
-
CaseIterable
协议: 遍历枚举内容,可以快速实现遍历枚举值 -
CustomStringDescription
协议,可以实现自定义打印描述
-
class CustomStringDescription: CustomStringConvertible {
var description: String{
"实现自定义描述内容"
}
}
enum Season: CaseIterable {
case spring, summer, autumn, winter
}
//遍历season
func testTravelSeason() {
let seasons = Season.allCases
print(seasons.count)
for season in seasons {
print(season)
}
}
元组
- Any、AnyObject
1. Swift提供了2中特殊的类型:Any
、AnyObject
2.Any
:可以代表任意类型(枚举、结构体、类,也包括函数类型)
3.AnyObject
: 可以代表任意类型(在协议后面写上:AnyObject
代表只有类能够遵守这个协议)
func testAny() {
var stu: Any = 10
stu = "Jack"
stu = Person(x: 10, y: 20)
//创建一个能够存放任意类型的数组
var data = [Any]()
data.append(10)
data.append(3.15)
data.append(Person(x: 10, y: 20))
data.append("Jack")
data.append({10})
}
-
is、as?、as!、as
使用
1.is
用来判断是否为某种类型,as
用来进行强制类型转换
2.as?
类似于可选链,如果转换成功,执行后序操作,如果转换不成功返回nil
3. 强制转换,转换出错会导致崩溃发生
func testAs() {
var student: Any = 10
(student as? Person)?.draw() //没有调用draw方法
student = Person(x: 10, y: 20)
(student as? Person)?.draw() //调用方法
(student as! Person).draw() //调用方法
var protocolInstance = student as? Drawable
protocolInstance?.draw() //调用方法
//以下会报错
// (student as? Drawable)?.draw()
}
-
X.self
、X.Type
、AnyClass
-
X.self
是一个元类型(metadata)的指针,metadata存放着类型相关的信息 -
X.self
属于X.Type
类型
-
func testTypeUse() {
class Person{}
class Student: Person{}
var perType: Person.Type = Person.self
var student: Student.Type = Student.self
perType = Student.self
var anyType: AnyObject.Type = Person.self
anyType = Student.self
typealias AnyClass = AnyObject.Type
var anyType2: AnyClass = Person.self
anyType2 = Student.self
var per = Person()
var perTypeTwo = type(of: per) // Person.self
print(Person.self == type(of: per)) // true
}
- 元类型的应用
- 动态创建实例对象
- 动态获取类型的一些信息内容
func typeSelfUse() {
class Animal { required init() { } }
class Cat: Animal { }
class Dog: Animal { }
class Pig: Animal { }
func create(_ clses: [Animal.Type]) -> [Animal]{
var arrar = [Animal]()
for cls in clses {
arrar.append(cls.init())
}
return arrar
}
}
-
Self
的使用-
Self
一般用作返回值类型,限定返回值与方法调用者必须是同一类型(也可以作为参数类型)
-
func testSelfUse() {
class Person: Runnable{
func test() -> Self { type(of: self).init() }
required init() { }
}
class Student: Person { }
var p = Person()
print(p.test())
var stu = Student()
print(stu.test())
}
Error异常处理
- Swift 中可以通过
Error
协议自定义运行时错误信息- 函数内部通过
throw
抛出自定义Error
,可能会抛出Error
的函数必须加上throws
声明 - 需要使用
try
调用可能会抛出Error
的函数 - 可以使用
do-catch
捕捉Error
- 函数内部通过
enum SomeError: Error {
case illegalArg(String)
case outOfBounds(Int, Int)
case outOfMemory
}
func divide(sourceNum: Int, divideNum: Int) throws -> Int {
if divideNum == 0 {
throw SomeError.illegalArg("非法字符")
}
return sourceNum/divideNum
}
func testError() {
do{
print(try divide(sourceNum: 10, divideNum: 0))
}catch{
switch error as? SomeError {
case let .illegalArg(msg):print(msg)
case let .outOfBounds(index, end):print("index: \(index) end:\(end)")
case .outOfMemory:print("内存溢出")
case .none: print("none error")
}
}
}
网友评论