Swiftで学ぶアクセス修飾子の使い方10選

Swiftのアクセス修飾子を解説するイラスト Swift
この記事は約15分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればサンプルコードを活用して機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Swiftを学んでいると、”アクセス修飾子”という言葉を耳にすることがあるでしょう。

しかし、これがどのようなもので、どのように使われるのかは、特に初心者にとっては少し難しいトピックの一つかもしれません。

この記事を読めば、Swiftでのアクセス修飾子の使用方法を10の具体的な例を通じて完璧に理解することができるようになります。

Swiftにおけるアクセス修飾子は、クラス、構造体、列挙体、そのメンバ(プロパティやメソッドなど)のアクセスレベルを制限するためのものです。

これによって、コードの安全性を高めたり、他の開発者に意図しない使い方をさせないように制御することが可能です。

●Swiftのアクセス修飾子とは

Swiftには複数のアクセス修飾子が存在しますが、それぞれの役割と使い方をしっかり理解することが、効果的なプログラムを書くための鍵となります。

○アクセス修飾子の基本

アクセス修飾子は、ある特定の部分のコードが、どこからアクセスできるか(またはできないか)を明示的に指定するためのものです。

例えば、あるクラスの内部でしか使用しないプロパティやメソッドを外部からアクセスできないようにするといった場合に利用します。

○Swiftでのアクセス修飾子の種類

Swiftには次のような主なアクセス修飾子が存在します。

  1. openpublic : 他のモジュールからアクセス可能。
  2. internal : 同じモジュール内からのみアクセス可能。これがデフォルトのアクセスレベルです。
  3. fileprivate : 同じソースファイル内からのみアクセス可能。
  4. private : 同じ宣言内、またはその延長(extension)内からのみアクセス可能。

これらのアクセス修飾子をうまく使うことで、コードの構造や設計をより柔軟に、そしてより安全に行うことができます。

●アクセス修飾子の使い方

Swiftでのアクセス修飾子は非常に強力で、適切に使うことでコードの可読性や保守性を高めることができます。

ここでは、Swiftでのアクセス修飾子の使い方を、具体的なサンプルコードを交えて詳しく解説していきます。

○サンプルコード1:publicなクラスの作成

publicというアクセス修飾子は、他のモジュールからもアクセスが許可されるものを表す修飾子です。

下記のコードでは、公開されるクラスPublicClassを作成しています。

このクラスは他のモジュールからも利用することができます。

public class PublicClass {
    var name: String = "Swift"
}

このコードを実行すると、PublicClassというクラスが作成され、任意の場所でこのクラスを利用することができます。

○サンプルコード2:privateなプロパティの実装

privateというアクセス修飾子は、宣言された要素がその宣言の中でのみアクセスできることを表します。

下記のコードでは、クラスPersonの中にprivateなプロパティsecretNameを持っています。

このプロパティは、Personクラスの外からはアクセスすることができません。

class Person {
    private var secretName: String = "秘密の名前"
    func revealSecret() -> String {
        return "秘密の名前は\(secretName)です。"
    }
}

このコードを実行すると、Personクラスをインスタンス化してrevealSecretメソッドを呼び出すと、"秘密の名前は秘密の名前です。"という結果を得ることができますが、secretNameに直接アクセスすることはできません。

○サンプルコード3:fileprivateを用いた同一ファイル内のアクセス

Swiftにおいて、fileprivateは非常に特別なアクセス修飾子として存在します。

この修飾子を使うと、宣言された要素は、同一のファイル内でのみアクセス可能となります。

他のファイルからはアクセスできないため、特定のファイル内でのみ使用されるプロパティやメソッドを定義する際に役立ちます。

下記のサンプルコードを考えてみましょう。

class MyClass {
    fileprivate var filePrivateProperty: String = "このプロパティは同一ファイル内からのみアクセス可能です"
}

extension MyClass {
    func displayProperty() -> String {
        return "filePrivatePropertyの値は、\(filePrivateProperty)です。"
    }
}

このコードを解説すると、MyClassというクラス内にfilePrivatePropertyというfileprivateなプロパティが定義されています。

同じファイル内のMyClassの拡張(extension)からはこのプロパティにアクセスできるため、displayPropertyメソッドはfilePrivatePropertyの値を取得して表示することができます。

このコードを実行すると、MyClassをインスタンス化し、displayPropertyメソッドを呼び出すことで、"filePrivatePropertyの値は、このプロパティは同一ファイル内からのみアクセス可能ですです。"という結果が得られます。

○サンプルコード4:internalを使ったモジュール内アクセス

Swiftのデフォルトのアクセスレベルはinternalです。

これは、その要素が定義されているモジュール内からのみアクセスが許可されることを意味します。

下記のサンプルコードでは、InternalClassというクラスをinternalとして定義しています。

internal class InternalClass {
    var internalProperty: String = "このプロパティはモジュール内からのみアクセス可能です"
}

このコードのInternalClassは、定義されているモジュール内であれば、どこからでも利用することができます。

ただし、このモジュールの外からはアクセスすることはできません。

○サンプルコード5:openを使用したサブクラスの作成

openは、他のモジュールでもサブクラスを作成できるクラスを表すアクセス修飾子です。

openで修飾されたクラスやメソッドは、他のモジュールからオーバーライドすることができます。

open class OpenClass {
    open var openProperty: String = "このプロパティは他のモジュールからもオーバーライド可能です"
}

class SubclassOfOpenClass: OpenClass {
    override var openProperty: String {
        didSet {
            print("openPropertyがオーバーライドされました")
        }
    }
}

上記のサンプルコードで、OpenClassというクラスにはopenPropertyというopenなプロパティが存在します。

これにより、SubclassOfOpenClassというサブクラスでこのプロパティをオーバーライドすることができます。

●アクセス修飾子の応用例

Swiftのアクセス修飾子は、単純なプロパティやメソッドの隠蔽だけでなく、より高度なプログラム設計にも役立ちます。

ここでは、その中でも特に実践的な応用例をいくつか取り上げて解説していきます。

○サンプルコード6:private(set)の活用

Swiftでは、プロパティのgetterとsetterのアクセスレベルを別々に指定することができます。

これにより、プロパティの読み取りは公開しつつ、書き込みは制限したい場合などに非常に有用です。

class UserAccount {
    public private(set) var balance: Double = 0.0

    func deposit(amount: Double) {
        if amount > 0 {
            balance += amount
        }
    }
}

このコードでは、UserAccountクラスにbalanceというプロパティが存在します。

このプロパティは外部から読み取りは可能ですが、直接の書き込みはできないように設計されています。

代わりに、depositメソッドを使って正の金額を預金することができます。

このコードを実行してUserAccountのインスタンスを作成し、depositメソッドを使用することで、外部から安全にbalanceプロパティを操作することができます。

○サンプルコード7:複数のアクセス修飾子を組み合わせた実例

時には、複数のアクセス修飾子を組み合わせて使用することで、より柔軟な設計が可能になります。

例えば、次のようにして、特定のメソッドだけを同一ファイルやモジュール内からのアクセスに制限しつつ、他のメソッドは公開するといったことができます。

public class AdvancedClass {
    public var publicProperty: String = "公開プロパティ"
    fileprivate func fileprivateMethod() {
        print("このメソッドは同一ファイル内からのみアクセス可能です")
    }
    internal func internalMethod() {
        print("このメソッドはモジュール内からのみアクセス可能です")
    }
}

このコードでは、AdvancedClassというクラスが定義されています。

このクラスの中には、publicPropertyという公開プロパティと、fileprivateMethodinternalMethodという2つのメソッドが定義されています。

fileprivateMethodは同一のファイル内からのみアクセスできるようになっているのに対し、internalMethodはそのモジュール内から自由にアクセスできるようになっています。

これにより、必要に応じてアクセスレベルを調整することができ、安全かつ効率的なプログラム設計を実現することができます。

○サンプルコード8:extensionとアクセス修飾子の組み合わせ

Swiftにおけるextensionは、既存の型に新しい機能を追加するための仕組みです。

その際、アクセス修飾子を用いて、追加される機能の可視性をコントロールすることが可能です。

例として、String型に新しいメソッドを追加することを考えてみましょう。

しかし、このメソッドは同一のモジュール内でのみ利用可能としたい場合、どのように実装するのかを見ていきます。

extension String {
    internal func myCustomFunction() -> String {
        return "カスタム機能を持つString: \(self)"
    }
}

このコードでは、String型にmyCustomFunctionというメソッドを追加しています。

このメソッドはinternalアクセス修飾子を使って宣言されているので、同一モジュール内からのみアクセス可能です。

このようにextensionを使って型に新しい機能を追加する際、アクセス修飾子を組み合わせることで、追加される機能の可視性を柔軟にコントロールすることができます。

このコードを実行すると、例えば次のような利用が可能です。

let sampleString = "Hello, Swift!"
print(sampleString.myCustomFunction()) // 出力結果: "カスタム機能を持つString: Hello, Swift!"

○サンプルコード9:プロトコルとアクセス修飾子の関係

Swiftのプロトコルもアクセス修飾子を持つことができます。

これにより、どのスコープからプロトコルを実装できるかを制限することができます。

public protocol CustomProtocol {
    func displayMessage()
}

このコードでは、CustomProtocolというプロトコルを定義しています。

このプロトコルはpublicアクセス修飾子を使って宣言されているので、他のモジュールからもアクセス可能です。

しかし、その具体的な実装はプロトコルを採用する型に委ねられます。

このプロトコルを実装する際、displayMessageメソッドの実装を提供する必要があります。

struct SampleStruct: CustomProtocol {
    func displayMessage() {
        print("SampleStructがCustomProtocolを採用しました!")
    }
}

このように、Swiftのプロトコルとアクセス修飾子を組み合わせることで、より明確かつ柔軟な設計が可能となります。

○サンプルコード10:アクセス修飾子を活用したライブラリの設計

ライブラリやフレームワークを設計する際、外部に公開するAPIと内部的にのみ使用するAPIを明確に分けることが重要です。

アクセス修飾子をうまく活用することで、このような設計が実現可能です。

public class LibraryAPI {
    public func externalFunction() {
        print("外部からアクセス可能な関数")
        internalFunction()
    }

    private func internalFunction() {
        print("ライブラリ内部でのみ利用される関数")
    }
}

このコードでは、LibraryAPIクラスにexternalFunctionという公開関数と、internalFunctionという非公開関数が定義されています。

公開関数は外部から利用可能ですが、非公開関数はライブラリの内部でのみ利用できるように設計されています。

●注意点と対処法

Swiftでアクセス修飾子を使用する際の注意点や一般的な誤解、そしてその対処法について考察していきます。

正確にアクセス修飾子を理解し、適切に使用することで、効果的なコード設計を実現できます。

○非推奨の使用とその理由

Swiftでは、過去のバージョンで使用されていたいくつかのアクセス修飾子やパターンが非推奨とされています。

これらを現代のSwiftで使用することは、コードの保守性や互換性の観点から避けるべきです。

例として、privatefileprivateの区別に関する変更があります。

初期のSwiftではprivateは同一ファイル内の同じ型内でのみアクセス可能でしたが、Swift 4以降では、privateはその宣言が含まれる拡張(extension)や型内でアクセス可能となりました。

そのため、現代のSwiftで同一ファイル内の任意の場所からアクセスしたい場合はfileprivateを使用します。

しかし、不要に広いスコープを持たせることなく、適切な範囲でアクセス制御を行うことが求められます。

○アクセス修飾子の間違った使い方

アクセス修飾子を誤って使用することで、予期しないバグやセキュリティの問題が発生する可能性があります。

□過度な公開

一般に、最も制約の厳しいアクセス修飾子をデフォルトとして使用し、必要に応じて範囲を拡張することが推奨されます。

しかし、すべてをpublicopenで定義すると、ライブラリやモジュールの内部実装が外部に露出してしまい、未来の変更が難しくなります。

public class ExposedClass {
    public var data: Int = 0
}

このコードでは、ExposedClassとそのプロパティdataが外部から自由にアクセスできるようになっています。

このような設計は、内部実装の変更を阻害する可能性があります。

□不要な制約

逆に、必要以上に制約をかけると、その型やメソッドの再利用性が低下します。

private class RestrictedClass {
    func doSomething() {
        print("Doing something!")
    }
}

このRestrictedClassは、同一ファイル内でしか利用できません。この制約が本当に必要かどうか、再考する価値があります。

●カスタマイズ方法

Swift言語は非常に柔軟性が高く、開発者が特定の要件に合わせて独自の実装や設計を行うことが可能です。

アクセス修飾子もその例外ではありません。

Swiftでは、アクセス修飾子の基本的な使い方だけでなく、カスタマイズの方法も提供されています。

ここでは、Swiftでのアクセス修飾子のカスタマイズ方法について深く探ることで、より柔軟なコード設計を目指します。

○カスタムアクセスレベルの作成と利用方法

実際にはSwiftには「カスタムアクセスレベル」を作成する機能は存在しません。

しかし、既存のアクセス修飾子を組み合わせることで、あたかもカスタムのような動作を実現することができます。

例として、あるクラス内のプロパティが同じクラス及びその拡張でのみ変更可能で、他からは読み取り専用としたい場面を考えます。

この時、private(set)修飾子を活用することで、この要件を満たすことができます。

public class CustomAccessLevelClass {
    // 外部からは読み取り専用、クラス及びその拡張からのみ変更可能
    public private(set) var readOnlyOutside: Int = 0
}

// 同じファイル内での拡張
extension CustomAccessLevelClass {
    func increment() {
        readOnlyOutside += 1 // こちらでは変更が許可されている
    }
}

このコードを実行すると、CustomAccessLevelClassのインスタンスのreadOnlyOutsideプロパティは外部から変更することができません。

しかし、クラス自体やその拡張からは変更が可能です。

まとめ

Swiftのアクセス修飾子は、オブジェクト指向プログラミングにおける情報のカプセル化をサポートし、コードの安全性と効率性を高めるための非常に重要な機能です。

この記事を通じて、Swiftにおけるアクセス修飾子の基本から応用、そしてカスタマイズ方法までを網羅的に学ぶことができたかと思います。

具体的なサンプルコードを交えながらの解説を通じて、アクセス修飾子の実際の利用シーンや適切な使用法、そしてそれに伴う注意点を理解することができたのではないでしょうか。

また、カスタマイズのセクションでは、既存のアクセス修飾子を組み合わせて新しい振る舞いを実現する方法を探求しました。

プログラミングにおける安全性は非常に重要です。Swiftのアクセス修飾子を適切に利用することで、意図しないデータの変更やアクセスを防ぎ、より安全で保守性の高いコードを書くことができます。

初心者から中級者まで、この記事がSwiftにおけるアクセス修飾子の理解と実践に役立つことを願っています。

今後のSwiftプログラミングの際に、本記事の内容を思い出し、より質の高いコードの実装に役立ててください。