JHHK

欢迎来到我的个人网站
行者常至 为者常成

11、可选链、协议、元数据

目录

可选链

/// 零、可选链
func optionalChain() -> Void {
    
    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 }
    }
    
    
    //1、可选项的属性、方法调用
    do{
        print("--------1--------")
        let person: Person? = Person()//可选项
        
        //age
        let age1 = person!.age()
        print(age1)//18
        let age2 = person?.age()
        print(age2)//Optional(18)
        
        //dog
        let dog1 = person?.dog
        print(dog1)//Optional
        let dog2 = person!.dog
        print(dog2)
        
        //car
        let car1 = person?.car
        print(car1)//Optional
        let car2 = person!.car
        print(car2)//Optional
        let car3 = person!.car!
        print(car3)//Car对象
        
        //如果可选项为nil,调用方法、下标、属性失败,结果为nil
        //如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
        //如果结果本来就是可选项,不会进行再次包装
    }
    
    
    //2、
    do{
        print("----------2---------")
        // 多个?可以链接在一起
        // 如果链中任何一个节点是nil,那么整个链就会调用失败
        let person:Person? = Person()
        let dog = person?.dog // Dog?
        print(dog)//Optional
        let weight = person?.dog.weight // Int?
        print(weight)//Optional
        
        
        //注意car是可选类型
        let car = person?.car
        let price = person?.car?.price // Int?
        print(price)
        
        
        
        if let _ = person?.eat() {// ()?
            print("eat调用成功")
        } else {
            print("eat调用失败")
        }
        
        if let age = person?.age() {
            print("age is ",age)
        }else{
            print("age 调用失败")
        }
    }
    
    
    //3、
    do{
        print("---------3----------")
        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
        print(num1)// Optional(10)
        
        var num2: Int? = nil
        num2? = 10
        print(num2)// nil
        
    }
    
    
    //4
    do{
        print("---------4----------")
        let dict: [String : (Int, Int) -> Int] = [
           "sum" : (+),
           "difference" : (-)
       ]
       let result = dict["sum"]?(10, 20)
       print(result)// Optional(30), Int?
       if let x = result  {
           print(x)//30
       }
    }
}

协议的使用1

/// 一、协议的使用1
/**
 协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)
 协议中定义方法时不能有默认参数值
 默认情况下,协议中定义的内容必须全部都实现
 也有办法办到只实现部分内容,以后的课程会讲到
 */
protocol Drawable1{
    func draw()
    var x:Int{get set}
    var y:Int{get}
    subscript(index:Int)->Int{get set}
}
func protocolUse1(){
    
    /**
     协议中定义属性时必须用var关键字
     实现协议时的属性权限要不小于协议中定义的属性权限
     协议定义get、set,用var存储属性或get、set计算属性去实现
     协议定义get,用任何属性都可以实现
     */

    //1、协议实现方式一
    do{
        print("-------1--------")
        class Person : Drawable1 {
            var x:Int = 0
            let y:Int = 0
            func draw() -> Void {
                print("Person draw")
            }
            subscript(index:Int)->Int{
                get{ index }
                set{ }
            }
        }
        
        let person = Person()
        person.draw()
        print(person[0])
    }
        
    
    //2、协议实现方式二
    print("-------2--------")
    do{
        class People:Drawable1{
            var x:Int{
                get{ 0 }
                set{ }
            }
            
            var y:Int{
                get{ 0 }
            }
            
            func draw() -> Void {
                print("People draw")
            }
            
            subscript(index:Int)->Int{
                get { index }
                set { }
            }
        }
        
        let people = People()
        people.draw()
        print(people[0])
    }
}

协议的使用2 class static

// 二、协议的使用2 class static
/**
 为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标
 */
protocol Drawable2 {
    static func draw()
}
func protocolUse2(){
    class Person : Drawable2 {
        static func draw () {
            print("Person draw")
        }
    }
    
    class People : Drawable2 {
        class func draw() {
            print("People draw")
        }
    }

    Person.draw()
    
    People.draw()
}

协议的使用3 mutating


// 三、协议的使用3 mutating
/**
 只有将协议中的实例方法标记为mutating
 才允许结构体、枚举的具体实现修改自身内存
 类在实现方法时不用加mutating,枚举、结构体才需要加mutating
 */
protocol Drawable3 {
    mutating func draw()
}
func protocolUse3(){
    //
    class Person : Drawable3 {
        var x : Int = 0
        func draw() -> Void {
            x = 10
            print("Person draw x = ",x)
        }
    }
    
    //
    struct People : Drawable3 {
        var x : Int = 0
        mutating func draw() -> Void {
            x = 10
            print("People draw x = ",x)
        }
    }
    
    let per = Person()
    per.draw()
    
    var peo = People()
    peo.draw()
}

协议使用4 init

//四、协议使用4 init
/**
 协议中还可以定义初始化器init
 非final类实现时必须加上required
 如果从协议实现的初始化器,刚好是重写了父类的指定初始化器那么这个初始化必须同时加required、override
 */
protocol Drawable4 {
    init(x:Int,y:Int)
}
func protocolUse4() -> Void {
    
    //非final类实现时必须加上required
    class Person1 : Drawable4 {
        required init(x:Int,y:Int) {
            print("x is ",x,"y is ",y)
        }
    }
    
    
    //final类实现时不必加上required
    final class Person2 : Drawable4 {
        init(x:Int,y:Int) {
            print("x is ",x,"y is ",y)
        }
    }
    
    
    class Person {
        init(x:Int,y:Int) {
            print("x is ",x , "y is ",y)
        }
    }

    //如果从协议实现的初始化器,刚好是重写了父类的指定初始化器那么这个初始化必须同时加required、override
    class Student : Person , Drawable4 {
        required override init(x:Int,y:Int) {
            print("x is ",x ,"y is ",y)
            super.init(x: x, y: y)
        }
    }
}

协议的使用5 init? init!

// 五、协议的使用5 init? init!
/**
协议中定义的init?、init!,可以用init、init?、init!去实现
协议中定义的init,可以用init、init!去实现
*/
protocol Drawable5 {
    init()
    init?(age:Int)
    init!(no:Int)
}
func protocolUse5(){
    class Person : Drawable5 {
        
        //协议中定义的init,可以用init、init!去实现
        required init() {}
        //required init!() {}
        
        //协议中定义的init?、可以用init、init?、init!去实现
        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 live()
}

protocol Workable : Runnable {
    func work()
}

func protocolInherit() -> Void {
    //1、协议的继承
    do{
        class Person : Livable & Workable{
            func work() {
                print("Person work")
            }
            
            func live() {
                print("Person live")
            }
            
            func run() {
                print("Person run")
            }
        }
        
        let per = Person()
        per.work()//Person work
        per.live()//Person live
        per.run()//Person run

    }
    

    //2、协议的组合
    do{
        
        class Animal : Runnable {
            func run() {
                print("Animal run")
            }
        }
        
        class Person : Livable {
            func live() {
                print("Person live")
            }
            
            func run() {
                print("Person run")
            }
        }
        
        class People : Livable & Workable{
            func work() {
                print("People work")
            }

            func live() {
                print("People live")
            }
            
            func run() {
                print("People run")
            }
        }
        
        
        
        //接收People或其子类实例
        func fn0(obj:People){
            print("fn0",type(of: obj))
        }
        fn0(obj: People())//fn0 People
        
        
        
        //接收实现了Runable协议的对象
        func fn1(obj:Runnable){
            print("fn1",type(of: obj))
        }
        fn1(obj: Animal())//fn1 Animal
        fn1(obj: Person())//fn1 Person
        fn1(obj: People())//fn1 People

        
        
        //接收实现了Livable和Workable协议的对象
        func fn2(obj:Livable & Workable){
            print("fn2",type(of: obj))
        }
        fn2(obj: People())//fn2 People
        
        
        
        //接收实现了Livable和Workable协议并且是People或其子类
        func fn3(obj:Livable & Workable & People){
            print("fn3",type(of: obj))
        }
        fn3(obj: People())//fn3 People
    }
}

系统提供的协议介绍

/// 七、系统提供的协议介绍
func protocolIntroduceInSystem() -> Void {
    //1、枚举的 CaseIterable 让枚举遵守CaseIterable协议,可以实现遍历枚举值
    do{
        print("---------1----------")
        enum Season:CaseIterable{
            case spring,summer,autumn,winter
        }
        
        let seasons = Season.allCases
        print(seasons.count)
        for season in seasons {
            print(season)
        }
    }
    
    //2、CustomStringConvertible
    do{
        print("---------2----------")
        /**
         遵守CustomStringConvertible、 CustomDebugStringConvertible协议,都可以自定义实例的打印字符串
         print调用的是CustomStringConvertible协议的description
         debugPrint、po调用的是CustomDebugStringConvertible协议的debugDescription
         */

        class Person:CustomStringConvertible & CustomDebugStringConvertible{
            var age = 0
            var name = "jack"
            var description: String{
                "age = \(age),name = \(name)"
            }
            
            var debugDescription : String {
                "debug:age = \(age),name = \(name)"
            }
        }
        print(Person())
        debugPrint(Person())
    }
}

any和anyObject

/// 八、any和anyObject
protocol anyProtocol:Any{/**该协议任何类型都能遵守*/}
protocol anyObjProtocol:AnyObject{/**该协议只有类类型能遵守*/}
func anyAndAnyObject() -> Void {
    /**
     Swift提供了2种特殊的类型:Any、AnyObject
     Any:可以代表任意类型(枚举、结构体、类,也包括函数类型)
     AnyObject:可以代表任意类类型(在协议后面写上: AnyObject代表只有类能遵守这个协议)
     在协议后面写上: class也代表只有类能遵守这个协议
     */
    
    class Person{}
    class Car{}
    
    //1、any类型
    do{
        print("---------1--------")
        var test:Any = 10
        test = Car()
        test = [1,2,3]
        test = Person()
        test = "jack"
        print(test)//jack
    }
    

    //2、AnyObject类型
    do{
        print("---------2--------")
        var test2:AnyObject = Person()
        test2 = Car()
        //test2 = LCTest() //struct会报错
        test2 = Person()
        //test2 = "Tom"
        //test2 = 10
        print(type(of: test2))//Person
    }
    
    
    //3、
    do{
        print("---------3--------")
        // 创建1个能存放任意类型的数组
        let ints:Array<Int> = [1,2,3]
        let objs:Array<AnyObject> = [Car(),Person()]
        let anys:Array<Any> = [1,2,Car(),"Jeny",Person()]
        print(ints,objs,anys,separator:"\n")
        
        //var newAny = Array<Any>()
        var newAny = [Any]()
        newAny.append(1)
        newAny.append("123")
        newAny.append(Car())
        print(newAny)
    }
}

其它总结

/// 九、其它总结
protocol Other11Pro {}
func other11(){
    
    class Car{}
    
    class Person{}
    
    class Student:Person & Other11Pro{
        func run() -> Void {
            print("Student Run")
        }
        func study() -> Void {
            print("Student Study")
        }
    }
    
   
    
    //1、is用来判断是否为某种类型,as用来做强制类型转换
    do{
        print("--------1---------")
        let a:Int = 10
        print(a is Int)//true
        print(a is String)//false
        
        let p = Person()
        let s = Student()
        let c = Car()
        print(p is Person)//true
        print(s is Student)//true
        print(s is Person)//true
        print(s is Other11Pro)//true
        print(c is Car)//true
        print(c is Other11Pro)//false
    }
    
    
    //2、 as as? as!
    do{
        print("--------2---------")
        var stu1:Any = 10
        print(stu1 as? Student)//nil
        //print(stu as! Student)//对nil解包崩溃

        
        var stu2 = Student()
        print(stu2 as? Student)//Optional(Student)
        print(stu2 as! Student)//Student
       
        
        
        //只有在确定的情况下才能使用as
        var stu3:AnyObject = Student()
        //let h3 = stu3 as Student
        
        var stu4:Student = Student()
        let h4 = stu4 as Any
        print(h4)//Student
        
        let d = 10 as Double
        print(d)//10.0
    }
    
    
    
    //3、X.self X.type AnyClass
    do{
        print("---------3--------")
        

        /**
         let p:Person = Person();
         p是一个指针,指向一块堆空间内存
         这块内存存放着一个对象.
         对象类型是Person类型
         
         
         Person.self是一个指针,指向metadata(存放着类型相关信息)
         Person.type是一个类型
         Person.self属于Person.Type类型

         
         let metaP:Person.type = Person.self;
         metaP是一个指针,指向一块堆空间内存
         这块内存存放着一个对象,这个对象叫做元对象
         对象类型是Person.type类型
         */
        

        
        
        /**
         pp变量的内存地址:
         (lldb) expression print(Mems.ptr(ofVal: &pp))
         0x00007ffeefbff198
         
         pp变量的内存内容
         (lldb) memory read/1xg 0x00007ffeefbff198
         0x7ffeefbff198: 0x0000000100776280

         (lldb) po pp
         <Person: 0x100776280>

         pp变量指向的堆空间的前 16个字节
         (lldb) memory read/2xg 0x100776280
         标记1:0x100776280: 0x0000000100050ac0 0x0000000400000002

         personType变量的地址
         (lldb) expression print(Mems.ptr(ofVal: &personType))
         0x00007ffeefbff418
         
          personType变量内存存储内容:
         (lldb) memory read/1xg 0x00007ffeefbff418
         标记2:0x7ffeefbff418: 0x0000000100050ac0

         标记1  与  标记 2 地址相同 证明Person.self 指向元类型
         */
        let pp = Person()
        print(type(of: pp.self))//Person
        let personType:Person.Type = Person.self
        print(type(of: personType))//Person.Type
        
        
        //  AnyObject.type 与 AnyClass 相同
        let personType1:Person.Type     = Person.self
        let personType2:AnyObject.Type  = Person.self
        let personType3:AnyClass        = Person.self
        print(type(of: personType1))//Person.Type
        print(type(of: personType2))//Person.Type
        print(type(of: personType3))//Person.Type
            
        
        //Student.self元类型 同样是 Person.self元类型的子类
        //多态:父类指针指向子类对象
        var personType4:AnyClass = Person.self
        personType4 = Student.self
        print(type(of: personType4))//Student.Type
    }
    
    
    do{
        print("----------4---------")
        
        class Person {
            var age:Int = 18
            var height:Int = 180
            func grow() -> Void {
                print("grow")
            }
            
            static func grow()->Void{
                print("static grow")
            }
        }
        
        let per:Person = Person()
        
        per.grow()          //grow
        per.self.grow()     //grow
        Person.grow()       //static grow
        Person.self.grow()  //static grow
        type(of: per).grow()//static grow
        
        print(Person.self == type(of: per))//true
        
        let perType = type(of: per)
        print(perType)//Person
        let perTypeType = type(of: perType)
        print(perTypeType)//Person.Type
        
        print(type(of: perTypeType))//Person.Type.Type
    }
}

元数据的应用

/// 十、元数据的应用
protocol Runnableb {
    func test() -> Self
}
func metaDataUse() -> Void {
    
    class Animal { required init() { } }
    class Cat : Animal { }
    class Dog : Animal { }
    class Pig : Animal { }
    
    
    do{
        print("----------1----------")
        func create(_ clses: [Animal.Type]) -> [Animal] {
            var arr = [Animal]()
            for cls in clses {
                //cls.init() 与 Cat() 作用相同
                arr.append(cls.init())
            }
            return arr
        }
        
        let array:[Animal] = create([Cat.self,Dog.self,Pig.self])
        for animal in array {
            print(type(of: animal))
        }
        
        /**
         Cat
         Dog
         Pig
         */
    }
    
    
    
    do{
        print("----------2----------")
        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
        
        
        
        
        //从结果可以看得出来,Swift还有个隐藏的基类:Swift._SwiftObject
        //可以参考Swift源码:
        //https://github.com/apple/swift/blob/master/stdlib/public/runtime/SwiftObject.h
        
        do{
            //Self一般用作返回值类型,限定返回值跟方法调用者必须是同一类型(也可以作为参数类型)
            class Person : Runnableb {
                var age = 0
                static var count = 10
                required init() { }
                func test() -> Self {
                    
                    print(self.age)
                    print(Self.count)
                    
                    //返回一个与调用者相同类型的对象
                    return type(of: self).init()
                }
            }
            class Student : Person {
                
            }
            
            
            let p = Person()
            print(type(of:p.test()))
            
            let stu = Student()
            print(type(of:stu.test()))
            
            /**
             0
             10
             Person
             0
             10
             Student
             */
        }
    }
}

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.