美文网首页
十三、可选链、协议、元类型

十三、可选链、协议、元类型

作者: 爱玩游戏的iOS菜鸟 | 来源:发表于2020-02-06 21:12 被阅读0次

    可选链

    可选链是一个调用和查询可选属性、方法和下标的过程,它可能为 nil

    • 如果可选项是 nil ,属性、方法或者下标的调用,结果为 nil
    • 如果可选项包含值,属性、方法或者下标的调用成功,结果会被包装为可选项
    • 多个?可以链接在一起,如果链中任何一个节点是 nil ,那么整个链就会调用失败。
    class Car {
        var price = 0
    }
    
    class Dog {
        var weight = 0
    }
    
    class Person {
        var name = ""
        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 age1 = person?.age()//Int? Optional(18)
    //强制展开则在可选项为 nil 时触发运行时错误
    var age2 = person!.age()//Int 18
    var name = person?.name//String? Optional("")
    var index = person?[6]//Int? Optional(6)
    
    if let result = person?.eat() {
        print("调用eat成功",result)//() 空元组
    }else{
        print("调用eat失败")
    }
    
    person?.eat()
    
    func getName()->String{
        print("getName:Jack")
        return "jack"
    }
    //如果person为nil 则不会调用getName()
    person?.name = getName()
    
    //多个?可以链在一起
    //如果链中任何一个节点为nil 那么整个链调用失败
    var dog = person?.dog//Dog?
    var weight = person?.dog.weight//Int?
    var price = person?.car?.price//Int?
    

    如果结果本来就是可选项,不会进行再次包装

    可选链的应用
    var scoreArr = ["jack":[86,85,98],
                    "rose":[56,64,23]
    ]
    var s = scoreArr["jack"]?[0]//Optional(86)
    
    var num1: Int? = 5
    num1? = 10//Optional(10) num1不是nil 则赋值
    
    var num2 :Int? = nil
    num2? = 10//nil num2为nil 则不赋值
    
    var dict: [String : (Int,Int) -> Int] = [
        "sum" : (+),
        "difference" : (-)
    ]
    var result = dict["sum"]?(10,20)//Optional(30)
    

    协议(Procotol)

    • 协议可以用来定义方法、属性、下标的声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)
    • 协议中定义方法时不能有默认参数值
    • 默认情况下,协议中定义的内容必须全部实现(如何只实现部分内容后期补充)
    协议中的属性
    1. 协议中定义属性时必须用var关键字
    2. 实现协议时的属性权限要不小于协议中定义的属性权限
    • 协议定义set、get,用var存储属性或用get、set计算属性实现
    • 协议定义get,用任何属性都可以实现(let存储属性或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 Animal: Drawable {
        var x: Int{
            set{ }
            get{ 0 }
        }
        var y: Int{0}
        func draw() {
            print("Animal draw")
        }
        subscript(index: Int) -> Int {
            set{ }
            get{ index }
        }
    }
    
    static、class关键字

    为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标

    protocol Drawable {
        static func draw()
    }
    
    //在遵循该协议的类的实现中,如果需要可以继承 可以改为class
    class Person: Drawable {
        static func draw() {
            print("Person Draw")
        }
    }
    
    class Animal: Drawable {
        class func draw() {
            print("Animal Draw")
        }
    }
    
    mutating

    只有将协议中的实例方法标记为mutating

    • 才允许结构体、枚举的具体实现修改自身内存
    • 类在实现方法时不用加mutating,枚举、结构体才需要加mutating
    protocol Drawable {
        mutating func draw()
    }
    
    //在类中,如果需要可以继承 可以改为class
    class Person: Drawable {
        var age: Int = 0
        
        func draw() {
            print("Person Draw")
            age = 10
        }
    }
    
    struct Point: Drawable {
        var x: Int = 0
        mutating func draw() {
            print("Animal Draw")
            x = 10//不加mutating 不可修改自身内存的值
        }
    }
    
    init
    • 协议中还可以定义初始化器init
    • final类实现必须加上required
      如果从协议实现的初始化器,刚好是重写了父类的指定初始化器,那这个初始化必须同时加requiredoverride
    protocol Drawable {
        init(x: Int,y: Int)
    }
    
    class Point: Drawable {
        var x: Int
        var y: Int
        
        required init(x: Int, y: Int) {
            self.x = x
            self.y = y
        }
    }
    
    final class Size: Drawable{
        var width: Int
        var height: Int
        init(x: Int, y: Int) {
            self.width = x
            self.height = y
        }
    }
    
    protocol Livable {
        init(age: Int)
    }
    
    class Person {
        var age: Int
        init(age: Int) {
            self.age = age
        }
    }
    
    //如果加上final 可以去掉required
    class Student: Person,Livable{
        required override init(age: Int) {
            super.init(age: age)
        }
    }
    
    init、init?、init!的区别
    • 协议中定义的init?、init! ,可以用init、init?、init!去实现
    • 协议中定义的init,可以用init、init!去实现
    protocol Livable {
        init(age: Int)
    //    init?(idNum:Int)
    //    init!(sex:String)
    }
    
    class Person :Livable {
        var age: Int = 0
        var idNum: Int = 0
        var sex: String = "men"
        
        required init(age: Int) {
            self.age = age
        }
        //required init!(age: Int) {//编译通过
            //self.age = age
        //}
        
        
        required init?(idNum: Int) {
            self.idNum = idNum
        }
        //required init!(idNum: Int) {//编译通过
                //self.idNum = idNum
            //}
        //required init(idNum: Int) {//编译通过
                //self.idNum = idNum
            //}
        
    
        required init!(sex: String) {
            self.sex = sex
        }
        //required init!(sex: String) {//编译通过
                //self.sex = sex
            //}
        //required init(sex: String) {//编译通过
                //self.sex = sex
            //}
    }
    
    协议的继承

    一个协议可以继承其他协议

    protocol Livable {
        func live(age: Int) -> String
    }
    
    protocol Runnable : Livable {
        func run(step: Int) -> String
    }
    
    class Person: Runnable {
        func run(step: Int) -> String {
            "\(step+1000)"
        }
        
        func live(age: Int) -> String {
            "\(age)"
        }
    }
    
    var person  = Person()
    print(person.live(age: 10),person.run(step: 1000))//输出:10 2000
    
    协议组合

    协议组合,可以包含1个类类型

    protocol Livable {
    }
    
    protocol Runnable {
    }
    
    class Person{
    }
    //接收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) { }
    
    CaseIterable

    让枚举遵守CaseIterable协议,可以实现遍历枚举值

    ![CaseIterable协议](https://img.haomeiwen.com/i7361389/a567ab3e43df54fe.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    enum Season :Int, CaseIterable {
        case spring = 0,summer,autumn,winter
    }
    
    let seasons = Season.allCases
    
    for season in seasons{
        print(season)
    }
    /* 输出:
     spring
     summer
     autumn
     winter
     */
    
    CustomStringConvertible

    遵守CustomStringConvertibleCustomDebugStringConvertible协议,都可以自定义实例的打印字符串

    class Person: CustomStringConvertible,CustomDebugStringConvertible {
        var age = 0
        var description: String {
            "person_\(age)"
        }
        
        var debugDescription: String {
            "debugperson_\(age)"
        }
    }
    
    var person = Person()
    print(person)//输出:person_0
    debugPrint(person)//输出:debugperson_0
    
    po 调用的是debugDescription

    print 调用的是CustomStringConvertible协议的description
    debugPrint、po指令 调用的是CustomDebugStringConvertible协议的debugDescription

    Any 、 AnyObject

    Swift提供了2中特殊的类型:Any 、 AnyObject

    • Any:可以代表任意类型(枚举、结构体、类以及函数类型)
    • AnyObject:可以代表任意类型(协议后面写上:AnyObject代表只有类可以遵守这个协议)

    协议后面写上class也代表只有类可以遵守这个协议

    class Student {}
    
    var stu: Any = 10
    stu = "jack"
    stu = Student()
    
    var data = [Any]()
    data.append("123")
    data.append(123)
    data.append(123.23)
    data.append(Student())
    data.append({10})//闭包表达式
    
    is、as?、as!、as
    • is用来判断是否为某种类型
    • as用来做强制类型转换
    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)//true
    
    //as用于强制类型转换
    var stu2:Any = 10
    (stu2 as? Student)?.study()//没有调用study()  前?为可能转换失败 后?为可选链
    
    stu2 = Student()
    (stu2 as? Student)?.study()//调用study()
    (stu2 as? Student)!.study()//调用study() !为强制解包
    (stu2 as! Student).study()//调用study() !为强制类型转换
    (stu2 as! Runnable).run()//调用run()
    

    元类型(metadata)

    • X.self是一个元类型的指针,metadata存放着类型相关信息
    • X.self属于X.Type类型(与X类型完全不同)
    X.self、 X.Type 、AnyClass
    class Person {}
    
    class Student: Person {}
    
    var perType: Person.Type = Person.self
    var stuType: Student.Type = Student.self
    perType = Student.self//编译通过
    
    var anyType: AnyObject.Type = Person.self
    anyType = Student.self
    
    public typealias AnyClass = AnyObject.Type
    var anyType2: AnyClass = Person.self
    anyType2 = Student.self
    
    var per = Person()
    perType = type(of: per)//Person.self
    print(Person.self == type(of: per))//输出:true
    
    元类型的应用
    class Animal {
        required init() {
            
        }
    }
    
    class Cat: Animal { }
    class Dog: Animal { }
    class Pig: Animal { }
    
    func create(_ classes:[Animal.Type]) -> [Animal] {
        var arr = [Animal]()
        for classType in classes {
            arr.append(classType.init())
        }
        return arr
    }
    
    print(create([Cat.self,Dog.self,Pig.self]))
    
    print(class_getInstanceSize(Cat.self))//输出:16
    print(class_getSuperclass(Dog.self)!)//输出:Animal
    print(class_getSuperclass(Animal.self))//输出:Optional(Swift._SwiftObject)
    

    从结果可以看的出来,Swift还有一个隐藏基类Swift._SwiftObject
    Swift runtime源码查看

    Self
    • Self代表当前类型
    • Self一般用作返回值类型,限定返回值跟方法调用者必须一致(也可用作参数类型)
    //Self代表当前类型
    class Animal {
        var age: Int = 1
        static var count: Int = 2
    
        func run() {
            print(self.age)//输出:1
            print(Self.count)//输出:2
        }
    }
    
    //Self一般用作返回值类型
    protocol Runnable {
        func test() -> Self
    }
    
    class Person : Runnable{
        required init() {
            
        }
        func test() -> Self {
            type(of: self).init()
        }
    }
    
    class Student: Person {
    }
    
    var p = Person()
    print(p.test())//Person
    
    var stu = Student()
    print(stu.test())//Student
    

    相关文章

      网友评论

          本文标题:十三、可选链、协议、元类型

          本文链接:https://www.haomeiwen.com/subject/alqexhtx.html