美文网首页
Swift5 _08_init_deint_可选链_协议_元类型

Swift5 _08_init_deint_可选链_协议_元类型

作者: MR_詹 | 来源:发表于2021-02-02 23:06 被阅读0次

    required

    required修饰指定初始化器,表明其所有子类都必须实现该初始化器(通过继承或重写实现)
    如果子类重写了required初始化器,也必须加上required,不用加上override

    class Person {
       required init() {
           
       }
       init(age:Int) {
           print(age)
       }
    }
    
    class Student : Person {
       init(score:Int) {
           super.init(age: 0)
       }
       required init() {
           super.init()
       }
    }
    

    属性观察器

    父类的属性在它自己的初始化器中赋值不会触发属性观察器,但是在子类的初始化器中赋值会触发属性观察器

    class Person {
        var age: Int {
            willSet {
                print("willSet",newValue)
            }
            didSet {
                print("didSet",oldValue,age)
            }
        }
        init() {
            self.age = 0
        }
    }
    
    class Student: Person {
        override init() {
            super.init()
            self.age = 1
        }
    }
    
    /// wllSet 1
    /// willSet 0 1
    var stu = Student()
    

    可失败初始化器

    类、结构体、枚举都可以使用init?定义可失败初始化器

    class Person {
        var name: String
        init?(name:String) {
            if name.isEmpty {
                return nil
            }
            self.name = name
        }
    }
    

    之前接触过的可失败初始化器

    var num = Int("123")
    
    enum Answer : Int {
      case wrong,right
    }
    var an = Answer(rawValue:1)
    

    (1)不允许同时定义参数标签、参数个数、参数类型相同的可失败初始化器和非可失败初始化器
    (2)可以用init!定义隐式解包的可失败初始化器
    (3)可失败初始化器可以调用非可失败初始化器非可失败初始化器调用可失败初始化器需要进行解包
    (4)如果初始化器调用一个可失败初始化器导致初始化失败,那么整个过程都失败,并且之后的代码都停止执行
    (5)可以用一个非可失败初始化器重写一个可失败初始化器 ,但反过来不可以

    反初始化器deinit

    deinit叫做反初始化器,类似于C++的析构函数OC的dealloc方法
    当类的实例对象被释放内存时,就会调用实例对象的deinit方法
    deinit不接受任何参数,不能写小括号,不能自行调用
    父类的deinit能被子类继承
    子类的deinit实现执行完毕后会调用父类的deinit

    class Person {
        deinit {
            print("person对象被释放了")
        }
    }
    

    可选链(Optional Chainning)

    (1)如果可选项为nil,调用方法、下标、属性失败,结果为nil
    (2)如果可选项不为nil,调用方法、下标、属性成功,结果会被包装成可选项
    (3)如果结果本来就是可选项不会进行再次包装
    (4)多个?可以链接在一起(如果链接中任何一个节点为nil,那么整个链就会调用失败

    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}
    }
    
    func getName() -> String {
        "Jack"
    }
    
    var person: Person? = Person()
    var age1 = person!.age()   /// Int
    var age2 = person?.age()    /// Int?
    var name = person?.name     /// String?
    var index = person?[6]      /// Int?
    
    /// 如果person为nil,那么不会调用getName()
    person?.name = getName()
    
    if let _ = person?.eat() {
        print("eat 调用成功")
    }else{
        print("eat 调用失败")
    }
    
    var dog = person?.dog   /// Dog?
    var weight = person?.dog.weight /// Int?
    var price = person?.car?.price  /// Int?
    
    
    
    var scores = [
        "Jack":[86,82,84],
        "Rose":[79,94,81]
    ]
    var num1: Int? = 5
    /// 表示num1不为nil的时候,才会个num1赋值10
    num1? = 10
    var num2: Int? = nil
    num2? = 10
    

    协议(Protocol)

    (1)协议可以用来定义方法、属性、下标声明,协议可以被枚举、结构体、类遵守(多个协议之间用逗号隔开)
    (2)协议中定义方法不能有默认参数值
    (3)默认情况下,协议中定义的内容必须全部实现

    protocol Drawable {
        /// 只做声明
        /// get set 表示可读可写
        /// get 表示只读
        /// 不限制属性是计算属性还是存储属性
        var x: Int {get set}
        var y: Int {get}
        func draw()
        subscript(index:Int) -> Int {get set}
    }
    
    
    protocol Test1 {}
    protocol Test2 {}
    protocol Test3 {}
    
    class TestClass: Test1,Test2,Test3 { }
    

    协议中的属性
    (1)协议中定义的属性时必须用var关键字
    (2)实现协议时的属性权限要不小于协议中定义 的属性权限
    协议定义get、set,用var存储属性或get、set计算属性去是实现
    协议定义get,用任何属性都可以是实现

    /// 方式一:存储属性
    class Person: Drawable {
        var x: Int = 0
        let y: Int = 0
        
        func draw() {
            print("Person")
        }
        
        subscript(index: Int) -> Int {
            get { index }
            set {}
        }
    }
    
    /// 方式二: 计算属性
    class Person : Drawable {
        var x: Int  {
            set{ }
            get{ 0 }
        }
        
        var y: Int { 0 }
        
        func draw() {
            print("Person draw")
        }
        
        subscript(index: Int) -> Int {
            set{}
            get{index}
        }
        
    }
    

    协议中的static、class
    为了保证通用,协议中必须用static定义类型方法、类型属性、类型下标
    (因为结构体和枚举也可以遵守协议,而clas只能是定义类的类型方法)

    protocol Drawable {
        static func draw()
    }
    
    class Person1: Drawable {
        class func draw() {
            print("Person1 draw")
        }
    }
    
    class Person2: Drawable {
        static func draw() {
            print("Person2 draw")
        }
    }
    

    协议中的mutating
    只有将协议中的实例方法标记为mutating
    才允许结构体、枚举的具体实现修改自身的内存(属性)
    类在实现方法时不用加mutating,枚举、结构体才需要加mutating

    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
    协议中还可以定义初始化器init
    非final类实现时必须加上required

    protocol Drawable {
        init(x:Int,y:Int)
    }
    
    class Size: Drawable {
        required init(x: Int, y: Int) {
            
        }
    }
    
    final class Point: Drawable {
        init(x: Int, y: Int) {
            
        }
    }
    

    如果从协议实现的初始化器,刚好是重写了父类的指定初始化器
    那么这个初始化器必须同时加上required、override

    
    protocol Livable {
        init(age:Int)
    }
    
    class Person {
        init(age:Int) {
            
        }
    }
    
    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()
        init?(age:Int)
        init!(no:Int)
    }
    
    class Person: 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) {}
    //    required init(no: Int) {}
    }
    
    

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

    protocol Runnable {
        func run()
    }
    
    protocol Livable : Runnable {
        func breath()
    }
    
    class Person: Livable {
        func run() {
            
        }
        
        func breath() {
            
        }
    }
    

    协议的组合
    协议组合,可以包含1个类类型(最多1个)

    protocol Runnable {}
    protocol Livable {}
    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
    func fn4(obj:RealPerson) {}
    

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

    enum Season : CaseIterable {
        case spring,summer,autumn,winter
    }
    
    let seasons = Season.allCases
    for season in seasons {
        print(season)
    }
    

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

    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: 18, name: "lili")
    /// age=18,name=lili
    print(p)
    

    Any、AnyObject

    Swift提供了2种特殊类型: Any、AnyObject
    Any: 可以代表任意类型(枚举结构体,也包括函数类型
    AnyObject: 可以代表任意类型(在协议后面写上:AnyObject表示只有类能遵守这个协议

    class Student {
    }
    
    var stu: Any = 10
    stu = "jack"
    stu = Student()
    
    
    var data = Array<Any>()
    data.append(1)
    data.append(3.14)
    data.append("jack")
    

    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")
        }
    }
    
    
    var stu: Any = 10
    print(stu is Int)       /// ture
    stu = "Jack"
    print(stu is String)    /// true
    stu = Student()
    print(stu is Person)    /// true
    print(stu is Student)   /// true
    print(stu is Runnable)  /// true
    
    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   
    
    

    X.self 、 X.Type、AnyClass

    X.self 是一个元类型(metadata)的指针,metadata存放着类型相关的信息
    X.self属于X.Type类型

    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()
    var 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(_ clses:[Animal.Type]) -> [Animal] {
        var arr = [Animal]()
        for cls in clses {
            /// 前提条件是: cls都有init初始化器,所有其父类中使用required修饰init
            arr.append(cls.init())
        }
        return arr
    }
    
    print(create([Cat.self,Dog.self,Pig.self]))
    

    Self

    Self 一般作返回值类型,限定返回值跟方法调用者必须是同一个类型(也可以作为参数类型)

    protocol Runnable {
        func test() -> Self
    }
    
    class Person: Runnable {
        required init() {}
        func test() -> Self {
            /// 返回的必须是调用者的类型
            /// 这里不能直接返回Person.init()
            /// 这是因为如果其子类调用这个方法那么返回的类型会对不上
            type(of: self).init()
        }
    }
    
    class Student : Person {}
    
    
    var p = Person()
    /// Person
    print(p.test())
    
    var stu = Student()
    /// Student
    print(stu.test())
    
    

    相关文章

      网友评论

          本文标题:Swift5 _08_init_deint_可选链_协议_元类型

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