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