Swiftで他のファイルの変数を呼び出す10選の方法

SwiftのロゴとプログラミングコードのスクリーンショットSwift
この記事は約20分で読めます。

 

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

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

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

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

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

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

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

はじめに

この記事を読めば、Swiftで他のファイルの変数を呼び出す方法をマスターすることができます。

プログラムを書く際、複数のファイルに分けてコードを管理することはよくあります。

このような場合、あるファイルの変数や関数を別のファイルから使いたくなることもあるでしょう。

そこで、今回はSwiftにおいて、他のファイルの変数や関数をどのように呼び出すのか、初心者目線で分かりやすく解説します。

●Swiftの基本的なファイル構造

Swiftプログラムの基本構造を理解することは、ファイル間の変数や関数の呼び出しをスムーズに行うための第一歩です。

○Swiftのファイルとは?

Swiftのファイルは主に.swiftという拡張子で保存されるソースコードファイルです。

一つのプロジェクトには複数の.swiftファイルが含まれることが多いです。

例えば、ユーザーインターフェースの部分と処理の部分を分けて、それぞれ別のファイルに記述することがあります。

Swiftには、変数や関数だけでなく、クラスや構造体、列挙型などの型も定義できます。

これらの型を定義したファイルから、別のファイルでその型や、型の中に定義された変数や関数を使用することができます。

○ファイル間のデータのやりとりの基本

Swiftのファイル間でのデータのやりとりを行う場合、いくつかのポイントを抑える必要があります。

まず、外部からアクセスするための変数や関数は、publicinternalなどのアクセスレベルを明示的に設定する必要があります。

逆に、外部からアクセスされたくない変数や関数は、privatefileprivateといったアクセスレベルを用いて保護することができます。

また、外部のファイルからアクセスする場合、その変数や関数が存在するファイルの型(クラスや構造体など)のインスタンスを作成するか、あるいはその型がstaticclassキーワードを用いて定義されている場合は、その型名を用いて直接アクセスすることが可能です。

●他のファイルの変数を呼び出す方法

Swiftを使ったプログラミングにおいて、他のファイルの変数や関数を呼び出す際の方法を理解することは、効率的なコードの書き方や整理、再利用性の向上につながります。

ここでは、Swiftで他のファイルの変数を呼び出す10の方法をサンプルコードと共に詳しく解説します。

○サンプルコード1:基本的な変数の呼び出し方法

Swiftでは、デフォルトで変数はinternalアクセスレベルを持っており、同じモジュール内の任意のファイルからアクセスすることができます。

例えば、DataFile.swiftというファイルに次のように変数を定義しているとします。

// DataFile.swift
var sharedData = "Hello from DataFile!"

このsharedData変数を、MainFile.swiftという別のファイルから呼び出すには、次のように直接使用します。

// MainFile.swift
print(sharedData) // 出力結果:Hello from DataFile!

このコードでは、DataFile.swiftに定義されたsharedData変数を使って、メッセージを出力しています。

このコードを実行すると、”Hello from DataFile!”というメッセージが出力されます。

○サンプルコード2:関数を通じて変数を呼び出す

変数を直接公開するのではなく、関数を通じて変数の値を取得したり、設定したりすることもよくあります。

これはカプセル化という考え方に基づいており、変数の直接的な変更を防ぐことができます。

例えば、次のような構造体がUserInfo.swiftというファイルに定義されているとします。

// UserInfo.swift
struct UserInfo {
    private var name = "John Doe"

    func getName() -> String {
        return name
    }

    mutating func setName(newName: String) {
        name = newName
    }
}

この構造体の変数nameprivateとして宣言されているので、外部から直接アクセスすることはできません。

しかし、getName()関数やsetName(newName:)関数を使えば、name変数の値を取得したり変更したりすることができます。

下記のように、MainFile.swiftという別のファイルからこの構造体を使用することができます。

// MainFile.swift
var user = UserInfo()
print(user.getName()) // 出力結果:John Doe

user.setName(newName: "Alice Smith")
print(user.getName()) // 出力結果:Alice Smith

このコードを実行すると、まず”John Doe”という名前が出力され、その後に”Alice Smith”という名前が出力されます。

○サンプルコード3:クラスや構造体を使った変数の呼び出し

Swiftでは、クラスや構造体を用いて複数の変数や関数を一つのまとまりとして扱うことができます。

これにより、他のファイルからもそのまとまりごとに変数を呼び出すことが可能となります。

例として、Person.swiftというファイルにPersonという構造体を定義し、その中にnameという変数を持たせることを考えます。

// Person.swift
struct Person {
    var name: String
}

この構造体をMainFile.swiftという別のファイルから利用して変数を呼び出す場合、次のように記述します。

// MainFile.swift
let someone = Person(name: "Taro")
print(someone.name)  // このコードを実行すると、"Taro"と表示されます。

このコードでは、Person構造体を使ってsomeoneというインスタンスを生成し、name変数に”Taro”という値を設定しています。

その後、print関数を用いてname変数の値を出力しています。

○サンプルコード4:プロトコルを利用した変数の呼び出し

Swiftにおけるプロトコルは、特定のメソッドやプロパティの機能を保証するための仕様書のようなものです。

これを利用することで、異なるファイルの変数も一定の規約のもとで呼び出すことができます。

例として、AnimalProtocol.swiftというファイルにAnimalというプロトコルを定義します。

// AnimalProtocol.swift
protocol Animal {
    var name: String { get }
    func makeSound() -> String
}

次に、Dog.swiftというファイルでこのプロトコルを採用したDogクラスを作成します。

// Dog.swift
class Dog: Animal {
    var name: String
    init(name: String) {
        self.name = name
    }

    func makeSound() -> String {
        return "ワンワン"
    }
}

最後に、MainFile.swiftからこのDogクラスを使用します。

// MainFile.swift
let myDog = Dog(name: "Pochi")
print(myDog.name)       // このコードを実行すると、"Pochi"と表示されます。
print(myDog.makeSound())  // このコードを実行すると、"ワンワン"と表示されます。

このコードを実行すると、まず”Pochi”という名前が出力され、その後にワンワンという音が出力されます。

○サンプルコード5:Extensionを利用した変数の呼び出し

SwiftのExtensionを利用すると、既存の型に新しい機能を追加することができます。

これにより、他のファイルで定義された変数や関数に追加の機能を持たせることが可能となります。

例えば、String型に数字だけで構成されているかどうかを判定する機能を追加する場合を考えます。

// StringExtension.swift
extension String {
    var isNumeric: Bool {
        return !isEmpty && rangeOfCharacter(from: CharacterSet.decimalDigits.inverted) == nil
    }
}

このExtensionを使用すると、MainFile.swiftで次のように文字列が数字のみで構成されているかどうかを判定できます。

// MainFile.swift
let str1 = "12345"
print(str1.isNumeric)  // このコードを実行すると、trueが表示されます。

let str2 = "ABC123"
print(str2.isNumeric)  // このコードを実行すると、falseが表示されます。

このコードを実行すると、最初にtrueが表示され、次にfalseが表示されます。

●応用的な変数の呼び出し方

Swiftの魅力はその柔軟性と拡張性にあります。

変数の呼び出しに関しても、基本的な方法からさまざまな応用的な方法まで存在します。

ここでは、Swiftで変数を呼び出す際の応用的な手法に焦点を当て、それぞれの方法をサンプルコードと共に詳しく解説していきます。

○サンプルコード6:ジェネリクスを用いた変数の呼び出し

ジェネリクスは、型に柔軟性を持たせるための強力なツールです。

ジェネリクスを利用することで、一つの関数やクラスをさまざまな型で再利用することができます。

例として、任意の型の配列の最初の要素を返す関数を考えます。

func firstElement<T>(_ array: [T]) -> T? {
    return array.first
}

let intArray = [1, 2, 3]
let firstInt = firstElement(intArray)  // このコードを実行すると、1が返されます。

let stringArray = ["apple", "banana", "cherry"]
let firstString = firstElement(stringArray)  // このコードを実行すると、"apple"が返されます。

このコードではジェネリクスを使用して、異なる型の配列を受け取ることができる関数を定義しています。

関数を呼び出す際に、整数の配列や文字列の配列を渡すことができ、それぞれの最初の要素を取得することができます。

○サンプルコード7:クロージャを通じて変数を呼び出す

Swiftのクロージャは、関数と非常に似ているもので、処理の塊を変数のように扱うことができます。

クロージャを使用することで、変数や関数を他の関数の引数として渡したり、関数から返すことができます。

例として、ある数値を2倍にするクロージャを考えます。

let doubleNumber: (Int) -> Int = { number in
    return number * 2
}

let result = doubleNumber(5)  // このコードを実行すると、10が返されます。

このコードは、整数を受け取り、その数を2倍にして返すクロージャを定義しています。

このクロージャを利用することで、5という数値を2倍にし、結果として10を取得することができます。

○サンプルコード8:デリゲートパターンを使った変数の呼び出し

デリゲートパターンはデザインパターンの一つであり、あるオブジェクトが特定のタスクやアクションの実装を他のオブジェクトに委譲することを可能にします。

Swiftにおいてもこのデリゲートパターンは非常に一般的に利用されます。

特にUI部品の動作をカスタマイズする場面などでよく見かけるパターンです。

下記のサンプルコードでは、DocumentというクラスがDocumentDelegateというプロトコルを利用して、文書の読み込み時の動作をデリゲート先に委譲する構造を表しています。

// デリゲートのためのプロトコルを定義
protocol DocumentDelegate: AnyObject {
    func documentDidReadContent(content: String)
}

class Document {
    weak var delegate: DocumentDelegate?

    var content: String? {
        didSet {
            if let content = content {
                delegate?.documentDidReadContent(content: content)
            }
        }
    }

    // 文書の内容を読み込む関数
    func readContent() {
        // 仮の文書内容を設定
        content = "Swiftのデリゲートパターンのサンプルコードです。"
    }
}

class DocumentReader: DocumentDelegate {
    func documentDidReadContent(content: String) {
        print("読み込んだ文書: \(content)")
    }
}

let document = Document()
let reader = DocumentReader()

document.delegate = reader
document.readContent()

このコードを実行すると、”読み込んだ文書: Swiftのデリゲートパターンのサンプルコードです。”と表示されます。

このコードではDocumentクラスが文書の内容を読み込む役割を持っており、文書を読み込んだ後の処理をDocumentDelegateというプロトコル経由でデリゲート先に委譲しています。

実際にはDocumentReaderクラスがこのプロトコルを採用し、文書読み込み後の具体的な処理(ここでは読み込んだ内容の表示)を実装しています。

○サンプルコード9:オブザーバーパターンを用いた変数の呼び出し

オブザーバーパターンは、あるオブジェクトの状態が変化した際に、それを購読している他のオブジェクトへ自動的に通知するデザインパターンです。

Swiftでは、このパターンを実装する方法としてNotificationCenterやプロパティオブザーバがあります。

ここでは、プロパティオブザーバを利用したオブザーバーパターンの一例を紹介します。

class ScoreManager {
    var score: Int = 0 {
        didSet {
            if score >= 100 {
                print("スコアが100を超えました!")
            }
        }
    }
}

let manager = ScoreManager()
manager.score = 50
manager.score = 150

このコードを実行すると、スコアが100を超えた際に”スコアが100を超えました!”と表示されます。

このコードでは、ScoreManagerクラス内のscoreプロパティにオブザーバを設定しており、このプロパティの値が変更されるたびに特定の処理を実行するようにしています。

特に、スコアが100を超えた場合にはメッセージを表示するようになっています。

このように、プロパティオブザーバを利用することで、変数の変更を監視して特定の処理を実行することが簡単にできます。

○サンプルコード10:Singletonパターンを利用した変数の呼び出し

Singletonパターンは、特定のクラスのインスタンスが一つしか存在しないことを保証するデザインパターンです。

Swiftでは、静的なプロパティとprivateなイニシャライザを組み合わせることで、Singletonパターンを簡単に実装することができます。

下記のサンプルコードは、設定情報を管理するConfigManagerクラスのSingleton実装を表しています。

class ConfigManager {
    static let shared = ConfigManager()

    var configuration: String?

    private init() {}

    func displayConfig() {
        if let config = configuration {
            print("現在の設定: \(config)")
        } else {
            print("設定がありません。")
        }
    }
}

ConfigManager.shared.configuration = "最適化設定"
ConfigManager.shared.displayConfig()

このコードを実行すると、”現在の設定: 最適化設定”と表示されます。

このコードでは、ConfigManagerクラスがSingletonとして実装されており、全体で一つのインスタンスしか生成されないようになっています。

そのため、どこからでもConfigManager.sharedを通じて同じインスタンスにアクセスでき、設定情報を一元的に管理することができます。

●Swiftでの呼び出し時の注意点と対処法

Swiftを使用して開発を行う際、他のファイルの変数や関数を呼び出すことは一般的な作業となりますが、いくつかの注意点が存在します。

これらの注意点を理解し、適切な対処法を知っておくことで、効率的に安全なコードを書くことができます。

○変数のスコープとアクセス制御

変数や関数は、それが定義されているスコープに基づいてアクセスされる必要があります。

Swiftでは、アクセス制御のキーワードを使って変数や関数の可視性を制御することができます。

// private: 同じファイル内からのみアクセス可能
private var privateVariable = "プライベート変数"

// fileprivate: 同じソースファイル内のどの型からもアクセス可能
fileprivate var fileprivateVariable = "ファイル内専用変数"

// internal: デフォルト。同じモジュール内からアクセス可能
internal var internalVariable = "内部変数"

// public: 他のモジュールからもアクセス可能だが、オーバーライドや継承は不可
public var publicVariable = "公開変数"

このコードの中で、それぞれのキーワードが付与された変数の可視性とアクセス範囲を表しています。

このようなアクセス制御を適切に使用することで、他のファイルやモジュールからの不要なアクセスを防ぐことができます。

○循環参照とその対処方法

循環参照は、オブジェクト同士が相互に強参照を持ってしまい、メモリの解放が行われなくなる現象を指します。

これはSwiftのクラス内で特に注意が必要な問題であり、メモリリークの原因となります。

下記のサンプルコードでは、循環参照の問題を表しています。

class Person {
    var car: Car?
    deinit {
        print("Personがメモリから解放されました")
    }
}

class Car {
    var owner: Person?
    deinit {
        print("Carがメモリから解放されました")
    }
}

var person: Person? = Person()
var car: Car? = Car()

person?.car = car
car?.owner = person

person = nil
car = nil

このコードでは、PersonCarという2つのクラスが相互に強参照を持っています。

その結果、どちらのオブジェクトもメモリから解放されない状況が発生します。

循環参照を防ぐための解決策として、Swiftではweakunownedといったキーワードを使用して、弱参照や非所有参照を作成することが推奨されています。

○エラー処理とtry-catch構文

Swiftでは、エラーを投げる関数やメソッドを呼び出す際にはtryキーワードを使用し、catchブロックでエラーを補足します。

enum ValidationError: Error {
    case invalidValue
}

func validate(value: Int) throws {
    if value <= 0 {
        throw ValidationError.invalidValue
    }
}

do {
    try validate(value: -5)
} catch {
    print("エラーが発生しました: \(error)")
}

このコードでは、validate関数がエラーを投げる可能性があり、そのエラーをdo-catch構文で補足しています。

エラーが発生すると、”エラーが発生しました: invalidValue”と表示されます。

このようなエラー処理を適切に行うことで、コードの安全性を高めることができます。

●Swiftの変数呼び出しのカスタマイズ方法

Swiftは柔軟性が高く、変数の呼び出し方法をカスタマイズするためのさまざまな方法が提供されています。

今回は、特に変数の呼び出しや利用におけるカスタマイズの手法について、アトリビュートの使用やプロパティラッパーの利用方法を中心に解説します。

○アトリビュートを用いたカスタマイズ

Swiftでは、変数や関数に特定の動作や特性を付与するためのアトリビュートが用意されています。

これにより、コンパイラの挙動をカスタマイズしたり、実行時の動作を制御することができます。

// @availableを使って特定のプラットフォームやバージョンでの利用を制限する例
@available(iOS 13, *)
var someFeatureForiOS13: String = "iOS 13以上で利用可能な機能"

上記のサンプルコードでは、@availableアトリビュートを使って、someFeatureForiOS13という変数がiOS 13以上のバージョンでのみ利用できるように制限しています。

○プロパティラッパーによるカスタマイズ

プロパティラッパーは、プロパティのセットや取得時の挙動をカスタマイズする強力なツールです。

独自のラッパーを作成することで、プロパティの保存方法やアクセス方法を変更することができます。

ここでは、値がセットされる際にログを出力するプロパティラッパーの一例を紹介します。

@propertyWrapper
struct Logging<Value> {
    private var value: Value
    var wrappedValue: Value {
        get { value }
        set {
            print("新しい値\(newValue)がセットされました")
            value = newValue
        }
    }

    init(wrappedValue: Value) {
        self.value = wrappedValue
    }
}

struct SomeStruct {
    @Logging var logValue: Int
}

var example = SomeStruct(logValue: 0)
example.logValue = 5

このコードを実行すると、logValueへの新しい値の設定時に、”新しい値5がセットされました”というログが出力されます。

プロパティラッパーを利用することで、変数へのアクセスや変更に関するロジックを一元的に管理することができ、コードの再利用性や可読性を高めることができます。

まとめ

Swiftのプログラミングにおいて、変数の呼び出しや利用は日常のタスクの中心となる部分です。

今回の記事では、基本的な呼び出し方法から応用的な方法、さらにはカスタマイズの手法まで、多岐にわたる内容を詳しく解説しました。

初心者から中級者の方々まで、Swiftでの変数の呼び出しや利用に関する知識や技術を深めることができる内容となっています。

特に、デリゲートパターンやオブザーバーパターン、プロパティラッパーなど、実際の開発現場で頻繁に利用されるテクニックに焦点を当てて解説してきました。

また、エラーハンドリングや循環参照の対処方法など、開発中に遭遇する可能性のある問題点とその解決策についても触れてきました。

これらの知識を活用することで、より質の高いSwiftのコードを書くことが可能となります。

Swiftの持つ柔軟性を活かし、変数の呼び出しや利用をカスタマイズする方法についても紹介しました。

これにより、特定の要件や目的に合わせて、効率的で安全なコードを実現することができます。

Swiftのプログラミングを学ぶ過程は、絶えず新しい発見や挑戦があるものです。

しかし、基本的な概念やテクニックをしっかりと理解しておくことで、その先の高度な内容もスムーズに学ぶことができるでしょう。

この記事が、皆様のSwiftプログラミングの学びの一助となれば幸いです。