LoginSignup
0
1

More than 1 year has passed since last update.

【SwiftUI】'〇〇' initializer is inaccessible due to 'private' protection level

Last updated at Posted at 2023-05-01

はじめに

次のようなSecondViewを作って、ContentViewからアクセスしようとしました。

SecondView.swift
struct SecondView: View {
    private var title = "Greeting"
    var text: String
    
    var body: some View {
        VStack {
            Text(title)
            Text(text)
        }
    }
}

titleはSecondViewでしか使わないし、private修飾子を付けてました。
すると、ContentViewの方でエラー。

ContentView.swift
struct ContentView: View {
    var body: some View {
        VStack {
            SecondView(text: "Hello")
            //'SecondView' initializer is inaccessible due to 'private' protection level
        }
        .padding()
    }
}

...???

結論

Memberwise InitializerによってContentViewからprivate varにアクセスしてしまっているので、自分でInitializerを作る

Memberwise Initializer

エラーの意味は、「privateレベルの変数があるので初期化子(イニシャライザ)にアクセスできません」といったもの。
ContentView.swiftの方にあった

SecondView(text: "Hello")

は、Memberwise Initializerというイニシャライザでstruct(SecondView)を初期化しています。
Memberwise Initializerは、自分でinitを設定しなかった場合に、struct の持つプロパティを全て初期化してくれるものです。
この「全て」が重要で、今回Memberwise Initializerで初期化しようとしたのはSecondViewtextだけではありません。すでに"Greeting"という初期値が設定されているprivate titleも同時に初期化しています。
例えばこんなこともできます。

struct Person {
    var name: String
    var age = 18
}

let janeDoe = Person(name: "Jane Doe", age: 20)

この場合、janeDoeというインスタンスは、nameが"Jane Doe"、ageが20として初期化されます。

つまり今回のエラーは、「titleを初期化しようとしたけど、アクセス範囲がprivateだったからできなかった」ということですね。
アクセス範囲については以下の記事を参照ください。
【Swift】アクセス修飾子【リファクタリング】

ちなみに、classにはMemberwise Initializerは存在しません。classはstructと違い継承機能があり、親クラスのプロパティが追加されるとそれを初期化に反映しないといけなくなるからです。詳しくは以下の記事を参照ください。
https://www.hackingwithswift.com/quick-start/understanding-swift/why-dont-swift-classes-have-a-memberwise-initializer

解決策

自分でinitを設定すればMemberwise Initializerは機能しなくなるのでエラーが消えます。

SecondView.swift
struct SecondView: View {
    private var title = "Greeting"
    var text: String
    init(text: String) {
        self.text = text
    }

    var body: some View {
        VStack {
            Text(title)
            Text(text)
        }
    }
}

SecondView内で定義したInitializerならprivateにもアクセスできるので、以下のような書き方もできます。

SecondView.swift
struct SecondView: View {
    private var title: String
    var text: String
    init(text: String) {
        self.text = text
        self.title = "Greeting"
    }

    var body: some View {
        VStack {
            Text(title)
            Text(text)
        }
    }
}

終わりに

以下の記事も参考にさせていただきました。
https://software.small-desk.com/development/2022/04/19/swift-explain-struct-initializer/
https://qiita.com/jinyogi/items/c1a7e29f086f206602bd

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1