所需初始化程序的访问控制规则似乎与未指定所需初始化程序的规则不同。为什么呢?
public class A {
// required init() must be public, why?
public required init() { }
}
public class B {
// init() does not need to be public, why?
init() { }
}
答案 0 :(得分:2)
首先,让我们明确规则。 required
初始值设定项不需要标记为public
。只需要required
初始值设定项与类一样可访问。如果您的课程为public
,则所需的初始值设定项也必须为public
。如果您的班级为internal
,则其必需的初始值设定项也必须为internal
(从技术上讲,您可以将其设为public
,但这样做没有意义并生成警告)。当然,如果您的课程为private
,则所需的初始值设定项也应为private
。
这里有两个原因,但它们需要了解required
关键字实际上在做什么。
首先,required
关键字保证此类及其所有子类实现此特定初始值设定项。需要初始化程序的主要原因之一是协议一致性,最常见的例子是NSCoding
,需要 init(coder:)
初始化程序。因此,考虑到这一点,让我们考虑一个试图实现该协议的类:
public class MySwiftClass: NSObject, NSCoding {
// some implementations
// including the two requirements of the NSCoding protocol
}
现在,考虑尝试使用它:
let mySwiftObject = MySwiftClass(coder: aCoder)
我们应该可以毫无问题地做到这一点,对吧?我的意思是,毕竟MySwiftClass
符合NSCoding
协议,NSCoding
协议保证会有init(coder:)
初始值设定项。
但是如果你被允许将init(coder:)
标记为比该类更低的访问级别,那么可以在其中看到类的范围,但是无法访问其所需的初始化程序...所以尽管知道这个类符合具有所需初始化程序的协议或者从具有所需初始化程序的父类继承,但我们不知何故无法调用所需的初始化程序,因为对于我们所处的范围,它会出现不存在。
第二个原因是对自身进行子类化。
让我们以此示例为父类:
public class ParentClass {
required init() {}
}
我们希望需要零参数初始值设定项。这意味着,如果任何内容继承自ParentClass
,则还必须确保实现了零参数初始化程序。但是如果我们被允许让所需的初始化程序具有比类本身更小的作用域,那么我们可以看到该类的作用域,但是我们看不到所需的初始化程序,那么在该作用域中创建的子类如何管理甚至知道他们必须实现所需的初始化程序?