Swift中的协议、元类型、Error异常处理

协议

  • 协议的特点
    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定义类型方法、类型属性、类型下标
    1. static是通用的,class只能在类中声明类型方法,为了保证通用,所以协议声明类型方法的时候需要使用static
    2. 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 问题
    这个初始化必须同时加上requiredoverride关键字修饰
    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!
    1. 协议中定义的init?/init!可以用init/init?/init!去实现
    2. 协议中定义的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. 一个协议可以继承其他协议
  2. 可以通过 & 组合多个类型的协议
  3. 协议组合,可以包含1个类类型(最多一个)
  4. 可以使用扩展 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) {}

}
   
  • 常见的系统自带的协议
    1. CaseIterable 协议: 遍历枚举内容,可以快速实现遍历枚举值
    2. 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中特殊的类型:AnyAnyObject
    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.selfX.TypeAnyClass
    1. X.self是一个元类型(metadata)的指针,metadata存放着类型相关的信息
    2. 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
        
    }
  • 元类型的应用
    1. 动态创建实例对象
    2. 动态获取类型的一些信息内容
    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的使用
    1. 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协议自定义运行时错误信息
    1. 函数内部通过 throw抛出自定义Error,可能会抛出Error的函数必须加上throws声明
    2. 需要使用 try调用可能会抛出Error的函数
    3. 可以使用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")
            }
        }
         
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 229,001评论 6 537
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 98,786评论 3 423
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 176,986评论 0 381
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,204评论 1 315
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 71,964评论 6 410
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,354评论 1 324
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,410评论 3 444
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 42,554评论 0 289
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,106评论 1 335
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 40,918评论 3 356
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,093评论 1 371
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 38,648评论 5 362
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,342评论 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 34,755评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,009评论 1 289
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 51,839评论 3 395
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,107评论 2 375

推荐阅读更多精彩内容