美文网首页从0到1学习Swift
Swift5 构造函数知识点总结

Swift5 构造函数知识点总结

作者: 一粒咸瓜子 | 来源:发表于2020-09-17 01:55 被阅读0次

    Swift 为类提供了两种构造器,分别是指定构造器和便利构造器。

    • 指定构造器必须总是向上代理(重写、重载)
    • 便利构造器必须总是横向代理

    重写构造函数

    override

    • 非 Optional 属性,都必须在构造函数中设置初始值,从而保证对象在被实例化的时候,属性都被正确初始化。

    • 顺序:分段进行,先初始化子类(保证必选属性有值),再初始化父类(super.init())。

      • super.init() 是对象构造结束的标记,可以省略但是不建议,保持代码执行线索的可读性。
      • 若使用属性,需要在子类初始化完成的时候
      • 若使用方法,要在初始化工作完成之后
    • Swift 中的构造函数不用写 func

    class Person: NSObject {
        var name: String // 必选属性需要在初始化器中赋初值
        /**
        重写 override
        父类已经存在的方法或者属性,子类需要重写做特殊操作的时候 可以重写。
        特点:在方法的内部可以 super
        */
        override init() {
            // name = "zhangsan"
            // Property 'self.name' not initialized at super.init call
            super.init()
        }
    }
    
    • UIViewController 是没有构造函数 init()的,所以可以直接写 init(),之后补上必须构造函数即可


      UIViewController 构造函数的重载

    重载构造函数

    overload:函数名相同,函数的参数类型或者参数的个数不同,函数就形成了重载,任何函数都可以形成重载

    如果本类构造函数发生了重载,本类中所有没有被重写的父类的构造函数都不能被访问
    原因:父类的构造函数无法完成分配空间和设置初始值的工作

    Person 重载了构造函数之后 override init,分配了name的值,所以实例化的时候可以使用 init()
    Student 重载了构造函数之后 没有 override init,实例化时无法确认age的值,所以无法使用 init()



    KVC构造函数(overload)

    class 继承 NSObject 才有 KVC 方法
    因为 swift 中没有 runtime,所以不建议使用 KVC
    原生支持的 json 转 model 是 Codable

    KVC 的 Model 使用必选属性,给予默认值
    所有参数前面加 @objc 或 在类前面加 @objcMember

    class model: NSObject {
        @objc var name: String?
        @objc var age: Int = 0
        
        init(dic: [String: Any]) {
            super.init()
            setValuesForKeys(dic)
        }
        //    override class func setValue(_ value: Any?, forKeyPath keyPath: String) {
        //        super.setValue(value, forKeyPath: keyPath)
        //    }
        //
        //    override func setValue(_ value: Any?, forUndefinedKey key: String) {
        //        print(key)
        //    }
    }
    

    便利构造函数

    convenience

    本身不负责创建对象,只是在init的外面添加了过滤条件,可能会创建失败返回nil。
    只有便利 convenience 的构造函数中才能以 self.init 的形式访问指定的构造函数。
    在分类中不能够定义指定的构造函数,必须使用便利构造函数

    条件判断,只有满足条件,才实例化对象,可以防治造成不必要的内存开销。
    便利构造函数具有以下特点:

    • 可以构造失败 返回 nil,
    • 只有便利构造函数中可以调用 self.init()
    • 必须调用同一类中定义的其他指定构造函数或者用 self. 的方式调用父类的便利构造函数
    • 便利构造函数不能被重写或者 super
    convenience init?(name: String, age: Int) {
        // 加拦截条件
        if age < 20 || age > 100 {
            return nil
        }
        // 指定初始化方法
        self.init(dict: ["name": name, "age": age])
        // 加工
        self.name = "zhangsan"
    }
    

    其他

    必要构造器

    实现其他构造器方法时必须要修改的默认构造器,如:UIViewController 的 init(coder:)

    逐一构造器

    官方文档中提到,结构体如果没有定义任何自定义构造器,它们将自动获得逐一成员构造器(memberwise initializer)。不像默认构造器,即使存储型属性没有默认值,结构体也能会获得逐一成员构造器。

    struct Size {
        var width = 0.0, height = 0.0
    }
    let twoByTwo = Size(width: 2.0, height: 2.0)
    // Swift 5.1 甚至会为你生成省去了有默认值属性的逐一构造器。省去的属性将会直接使用默认值
    let zeroByTwo = Size(height: 2.0)
    let twoByZero = Size(width: 2.0)
    

    某些场景下,如果确实需要自定义一个构造器,但又想保留逐一成员构造器,那么请在 extension 中自定义构造器。

    不过对于类来说,所有的构造器都必须自己来实现。所以从使用便利性的角度来说,结构体无疑是一个更好的选择。

    可失败构造器

    在 Swift 中可以定义一个构造器可失败的类,结构体或者枚举。这里的“失败”指的是,如给构造器传入无效的形参,或缺少某种所需的外部资源,又或是不满足某种必要的条件等。
    为了妥善处理这种构造过程中可能会失败的情况。你可以在一个类,结构体或是枚举类型的定义中,添加一个或多个可失败构造器。其语法为在 init 关键字后面添加问号(init?)。比如 Int 存在如下可失败构造器:

    init?(exactly source: Float)
    

    参考资料:
    由一个Crash引发对 Swift 构造器的思考

    相关文章

      网友评论

        本文标题:Swift5 构造函数知识点总结

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