【问题标题】:Access control for required init所需初始化的访问控制
【发布时间】:2015-11-22 09:00:23
【问题描述】:

必需初始化程序的访问控制规则似乎与未指定必需初始化程序的规则不同。为什么?

public class A {
  // required init() must be public, why?
  public required init() { }
}

public class B {
  // init() does not need to be public, why?
  init() { }
}

【问题讨论】:

  • 这里需要注意的是,这只是这种情况,因为类本身被标记为public。如果类本身没有访问修饰符并假定默认为 internal,那么您的 required 初始化程序也不需要访问修饰符。
  • @nhgrif 看看我回答中的粗体字。所需的 init 仍然需要一个至少为 internal 的访问修饰符,这是默认值,因此我们可以省略它。
  • 我不认为我的评论和你的回答存在分歧,@RMenke
  • @nhgrif 只是想澄清一下,不正确;)

标签: swift access-control initializer


【解决方案1】:

首先,让我们明确规则。不需要将 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,它还必须确保实现了零参数初始化程序。但是如果我们可以让 required 初始化器的作用域小于类本身,那么就有一个作用域可以看到类,但是我们看不到所需的初始化器,那么在该作用域中创建的子类如何管理甚至知道他们必须实现一个必需的初始化程序吗?

【讨论】:

  • 我被否决了。如果有人愿意解释我所犯的错误,或者我的答案可以如何改进,我很乐意更新答案。
  • 不是我,我觉得很好。但是在百万次编辑之后,我又一次搞砸了自己的答案。我快要放弃这个 Q/A 了。这个问题绝对不值得投反对票。
  • 我也不是。 SO 确实应该改进这方面。
猜你喜欢
  • 1970-01-01
  • 2012-10-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多