因为结构体初始化器在其所在文件中被限制为私有保护级别,所以无法访问。

30

我使用 Swift 4 在同一文件中定义了两个结构体,其中一个是私有的,所以只有该文件才能访问它。此外,我依赖于结构体的默认/合成初始化程序,也就是说,我没有显式地定义一个初始化程序:

private struct A {
  private let string: String
  ...
}

struct B {
  func foo() {
    let a = A(string: "bar")
    ...
  }
}

然而,使用以下代码会导致编译错误:

'A' initializer is inaccessible due to 'private' protection level

我不想让其他文件可以访问 A,因此尝试通过将其设置为 fileprivate(在这种情况下应该等效于 private)来解决,但是仍然会出现相同的编译错误(并且仍然抱怨保护级别是 private)。

有没有办法保持这个结构体是 fileprivate 并且仍然获得一个合成的初始化程序,可以公开所有未初始化的属性?例如: A.init(string:)

4个回答

39

事实证明,“私有访问级别”投诉是关于 initializer,而不是结构体。初始化程序的访问级别只能像最不可访问的实例变量一样可访问。

如果我将 string 实例变量设置为除 private 以外的任何其他值,则错误会消失:

private struct A {
  let string: String
  // synthesized initializer:
  // init(string: String)
}

鉴于B现在可以读取Astring,它也可以访问A的初始化程序。

但如果A有另一个private属性,则其初始化程序将再次变为private

private struct A {
  let string: String
  private let int: Int
  // synthesized initializer:
  // private init(string: String, int: Int)
  ...
}

那么你认为初始化程序只能像最不可访问的变量一样被访问吗? - Jace
我在一个SwiftUI项目中遇到了这个问题,它的行为让我感到困惑。 - Jace

4
您可以定义初始化器,这将有助于保持此结构的私有性。主要问题是,编译器会自动添加具有私有访问级别的初始化器private init(string: String),但您可以通过定义自己的初始化器来解决此问题。
private struct A {
    private let string: String

    fileprivate init(string: String) {
        self.string = string
    }

    func foo() {}
}

struct B {
    func bar() {
        A(string: "baz").foo()
    }
}

或者你可以使用fileprivate访问级别来处理string属性。这样,你就不需要初始化器。

private struct A {
    fileprivate let string: String

    func foo() {}
}

struct B {
    func bar() {
        A(string: "baz").foo()
    }
}

谢谢,不过 OQ 说:“我如何避免显式初始化程序”。 - Gobe
1
在这种情况下,您应该为“string”属性使用“fileprivate”访问级别。请检查我上面编辑过的答案。 - Nick Rybalko

0

这里有另一种解决 SwiftUI 结构体工作时可能出现的错误的方法。

由于变量未初始化或编译器不知道该变量是否保证具有值,因此给定此代码将产生相同的错误。

struct MyView: View {
    // Compiler: ¯\_(ツ)_/¯ 
    // initializer is inaccessible due to 'private' protection level
    private var rows: [Int]

    var body: some View {
        Text("Some text")
    }
}

所以你可以将其设置为可选类型、强制解包或者初始化一个值。

struct MyView: View {
    // Initialized
    private var rows = [Int]()

    var body: some View {
        Text("Some text")
    }
}

当实例化MyView()时,编译器不会报错。

struct MyView_Previews: PreviewProvider {
    static var previews: some View {
        MyView()
    }
}

编译器不会抱怨你这样做,但它也不允许你在初始化中注入任何内容 - 因为你的属性是私有的,所以它不会在生成的初始化程序中公开。原始问题是“如何避免显式初始化”,我将编辑它以使其更清晰,即我仍然希望该init具有参数。 - Gobe

-2

我使用了

private let s: String = "Some value"

对我来说它有效。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接