Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Struct initializer is inaccessible due to private protection level from its own file

Tags:

swift

Using Swift 4, I have defined two structs in the same file, where one of them is private so this file is the only one that can access it. Also I'm relying on the struct's default/synthesized initializer i.e. I'm not explicitly defining one:

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

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

However this will fail to compile with the following error:

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

I don't want to have A accessible to other files, so I tried to work around it by making it fileprivate (which should be equivalent to private in this scenario), but the same compilation error will occur (and it still complains that the protection level is private).

Is there a way to keep this struct fileprivate and still get a synthesized initializer that exposes all uninitialized properties? i.e. A.init(string:)

like image 670
Gobe Avatar asked Jun 12 '18 05:06

Gobe


Video Answer


2 Answers

It turns out that the "private access level" complaint was regarding the initializer, not the struct. The initializer's access level is only as accessible as the most accessible instance variable.

If I make the string instance variable anything other than private, the error goes away:

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

So given that B can now read A's string, it can also access A's initializer.

If A had another private property though, then again its initializer would become private:

private struct A {
  let string: String
  private let int: Int
  // synthesized initializer:
  // private init(string: String, int: Int)
  ...
}
like image 81
Gobe Avatar answered Oct 05 '22 13:10

Gobe


You can define initializer. It will help you to keep this structure private. The main problem is private let string compiler automatically add initializer with private access level private init(string: String).

For fix you have to define your own initializer

private struct A {
    private let string: String

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

    func foo() {}
}

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

Or you can use fileprivate access level for string property. In this case you don't need initializer.

private struct A {
    fileprivate let string: String

    func foo() {}
}

struct B {
    func bar() {
        A(string: "baz").foo()
    }
}
like image 35
Nick Rybalko Avatar answered Oct 05 '22 11:10

Nick Rybalko