Swift5 构造函数知识点总结

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 构造函数知识点总结)