Initializers in Swift Class

409 阅读3分钟

深入理解代替单纯记忆

  1. Swift初始化时会想尽一切办法确保初始化的安全、完备

  2. 就两种初始化方法:designated initializerconvenience initializer

  3. designated方法是指当前类完成初始化最基础的方法,它能满足所有stored property的初始化赋值

  4. 初始化方法中必须保证所有stored property都被赋上初始值。当然,optional的属性可以不用明显的写出,默认会赋值为nil

  5. Swift初始化方法,子类一般不会将父类的designated initializer方法继承下来。为的就是,一旦可以继承的话,那我们就可以用父类的方法初始化一个子类对象了,此时子类的对象的属性可能并不ok

    class Food {
        var name: String
        init(name: String) {
            self.name = name
        }
    }
    class Noodle: Food {
        let width: CGFloat
        init(width: CGFloat) {
            self.width = width
            super.init(name: "Noodle")
        }
    }
    
  6. 当然,上面所说是指一般情况,有些情况下子类还是会继承父类的designated initializer方法的

    • 就是子类没有自定义designated initializer
    • 如果子类有实现designated initializer,即使子类并没有增加stored property的情况下,此时子类依然不会继承父类初始化方法。因为自定义initializer初始化方法中除了为stored property赋值,可能还有其他自定义操作,既然写了designated initializer方法,就说明可能有自己的实现,此时再继承了父类的实现就触发4中的问题了
    class Food {
        var name: String
        init(name: String) {
            self.name = name
        }
        convenience init() {
            self.init(name: "unknown")
        }
    }
    class Noodle: Food {
    }
    let var1 = Noodle()
    let var2 = Noodle(name: "noddle")
    
  7. 一个复杂点的例子

    • Food是父类,RecipeIngredient是子类
    • 子类自定义实现了一个designated initializer,又重写了一个父类的designated initializer同时用作convenience initializer
    • 该情况下,父类的convenience init()方法会自动继承到子类中,因为子类实现了所有的的父类的designated initializer,所以父类的convenience initializer自动继承下来仍然会保证初始化的完备性

  8. 接着上面的例子,再来一层

    • ShoppingListItem作为更子的类,由于引入的purchased属性有默认值,所以会自动继承父类的各种初始化方法,因为继承下来不会影响初始化的完备性

简单总结

还是那句话,为了确保初始化的完备性,能继承下去的就继承,一旦发现有影响完备性的漏洞,就不允许继承

  • convenience initializer只能访问本类的初始化方法为此目的
  • designated initializer只能执行父类的designated initializer也是如此
  • 所有规则都是如此;不记规则,只看原则

疑问

  1. 一方面Swift的子类不能继承父类的初始化方法,另一方面,子类在重写父类的初始化方法时却仍要写上override,这点不是很理解
    • 如果不能继承父类初始化方法,那子类实现和父类一致的初始化方法时照理应该理解为定义了一个全新的初始化方法,而非真的重写了