Swiftでのクラス変数活用法!完全ガイドの10選

Swift言語でのクラス変数の使い方を詳しく解説するイメージSwift
この記事は約17分で読めます。

 

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

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

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

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

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

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

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

はじめに

Swiftを学び始めると、多くの概念に触れることになります。

その中でも「クラス変数」は、オブジェクト指向プログラミングの中核をなすトピックの一つです。

この記事を読むことで、Swiftのクラス変数の基本から応用、さらにはカスタマイズの方法までを習得することができるようになります。

具体的なサンプルコードを交えながら、初心者から中級者までの読者が理解しやすいように、一歩一歩詳しく説明していきます。

●Swiftとクラス変数とは

○Swift言語の概要

Swiftは、Appleが開発したプログラミング言語で、iOSやmacOSなどのアプリケーション開発に広く利用されています。

その特徴として、高速性、セキュリティ、そして直感的な文法が挙げられます。

SwiftはCやObjective-Cとの互換性も持ちつつ、より簡潔で読みやすいコードを実現することを目指して設計されました。

○クラス変数の基本

クラス変数とは、オブジェクト指向プログラミングにおいて、あるクラス全体で共有される変数を指します。

Swiftでは、staticキーワードを用いてクラス変数を宣言することができます。

クラス変数は、そのクラスのすべてのインスタンス間で共有されるため、一つのインスタンスでの変更が、他のすべてのインスタンスにも反映される特性を持っています。

例えば、あるゲームのプレイヤークラスがあり、そのゲーム全体での最高スコアを記録したい場合などに、クラス変数を活用することが考えられます。

●Swiftでのクラス変数の使い方

Swiftにおけるクラス変数の利用は、データをクラス全体で共有する際に非常に便利です。

そのため、多くのシチュエーションで活用されることが期待されます。

ここでは、クラス変数の具体的な使い方をサンプルコードを交えて詳しく見ていきます。

○サンプルコード1:基本的なクラス変数の定義と利用

Swiftでクラス変数を定義する際には、staticキーワードを使用します。

このキーワードを使うことで、クラスレベルで変数を宣言・利用できるようになります。

class Game {
    static var highestScore: Int = 0
}

// クラス変数にアクセス
print(Game.highestScore)  // 0

// クラス変数の値を更新
Game.highestScore = 100

print(Game.highestScore)  // 100

このコードでは、Gameクラス内にhighestScoreというクラス変数を定義しています。

そして、クラス名を用いてその変数にアクセスし、値を読み取ったり更新したりしています。

実行すると、初めに0が出力され、次に100が出力される結果となります。

○サンプルコード2:クラス変数を使用した計算

クラス変数は、計算や処理の中での利用も可能です。

例えば、ゲームのスコアの平均を計算する際などに活用することができます。

class Player {
    static var totalScore: Int = 0
    static var playerCount: Int = 0

    var score: Int {
        didSet {
            Player.totalScore += score
            Player.playerCount += 1
        }
    }

    init(score: Int) {
        self.score = score
    }

    static func averageScore() -> Double {
        return Double(totalScore) / Double(playerCount)
    }
}

let player1 = Player(score: 80)
let player2 = Player(score: 90)
let player3 = Player(score: 85)

print(Player.averageScore())  // 85.0

このコードでは、Playerクラスを定義し、その中にtotalScoreplayerCountという2つのクラス変数を持っています。

プレイヤーが新しく追加されるたび、そのスコアがtotalScoreに加算され、playerCountが1増えます。

そして、averageScoreメソッドを用いて平均スコアを計算しています。

この例を実行すると、85.0という結果が得られます。

○サンプルコード3:クラス変数とインスタンス変数の違い

Swiftの中で、変数は大きく「クラス変数」と「インスタンス変数」の二種類に分けられます。

これらの変数は、その名の通り、使い方や定義方法が異なります。

まず、クラス変数は、クラス自体に紐づく変数で、そのクラスの全インスタンスで共有される値を持ちます。

対照的に、インスタンス変数は各インスタンスごとに異なる値を持つことができます。

下記のサンプルコードでは、クラス変数とインスタンス変数の動作の違いを表しています。

class Animal {
    static var totalAnimals: Int = 0  // クラス変数
    var name: String                  // インスタンス変数

    init(name: String) {
        self.name = name
        Animal.totalAnimals += 1
    }
}

let dog = Animal(name: "Dog")
let cat = Animal(name: "Cat")

print(Animal.totalAnimals) // 2
print(dog.name)            // Dog
print(cat.name)            // Cat

このコードではAnimalというクラスを定義し、その中でtotalAnimalsというクラス変数と、nameというインスタンス変数を持っています。

新しいAnimalインスタンスが作成される度に、totalAnimalsが1ずつ増えます。

このように、クラス変数は全インスタンスで共有されるため、2つのインスタンスを作成した結果、totalAnimalsの値は2となります。

○サンプルコード4:クラス変数のアクセス制御

Swiftでは、変数のアクセス制御を細かく設定することができます。

これにより、変数の読み取りや書き込みの許可をクラス内、またはそのモジュール内に限定することが可能です。

この機能は、クラス変数にも適用できます。

下記のサンプルコードでは、クラス変数のアクセス制御を表しています。

class Bank {
    static private var totalMoney: Int = 1000000
    var personalMoney: Int

    init(money: Int) {
        self.personalMoney = money
    }

    static func donate(amount: Int) {
        if totalMoney - amount >= 0 {
            totalMoney -= amount
        }
    }
}

let person1 = Bank(money: 50000)
Bank.donate(amount: 1000)

// print(Bank.totalMoney)  // コンパイルエラー。private変数のため外部からアクセス不可

Bankクラスには、totalMoneyというprivateなクラス変数があります。

この変数はBankクラスの外から直接アクセスすることはできません。

しかし、donateメソッドを通じて間接的にその値を変更することは可能です。

上記の例では、直接totalMoneyにアクセスしようとするとコンパイルエラーが発生します。

●クラス変数の応用例

Swiftのクラス変数は、その特性上、多岐にわたる応用が考えられます。

クラス変数は、そのクラスに関連する情報を一元的に管理するのに役立ちます。

ここでは、クラス変数を使ったいくつかの代表的な応用例を取り上げ、サンプルコードとともに詳しく解説します。

○サンプルコード5:クラス変数を活用したシングルトンパターン

シングルトンパターンは、あるクラスのインスタンスがアプリケーション内で一つしか存在しないことを保証するデザインパターンの一つです。

クラス変数はこのシングルトンパターンを実装する際の強力な助け手となります。

class DatabaseManager {
    static let shared = DatabaseManager()
    var connection: String?

    private init() {}

    func connect() {
        connection = "Connected to Database"
    }
}

let dbManager = DatabaseManager.shared
dbManager.connect()
print(dbManager.connection!) // Connected to Database

このコードでは、DatabaseManagerクラスにsharedというクラス変数を持っており、この変数はDatabaseManagerの唯一のインスタンスを保持します。

init()メソッドがprivateであるため、外部からのインスタンス化は不可能となっており、sharedを通じてのみインスタンスにアクセスすることができます。

○サンプルコード6:クラス変数とメソッドの連携

クラス変数は、クラスメソッドとの連携も考えられます。

クラス変数を使用して、メソッドの動作をカスタマイズすることができます。

class User {
    static var userType: String = "Guest"

    class func displayGreeting() {
        if userType == "Guest" {
            print("ようこそ、ゲストユーザー様!")
        } else {
            print("ようこそ、\(userType)様!")
        }
    }
}

User.displayGreeting()  // ようこそ、ゲストユーザー様!

User.userType = "Admin"
User.displayGreeting()  // ようこそ、Admin様!

上記のコードは、UserクラスにuserTypeというクラス変数を持っています。

displayGreetingメソッドはこのuserTypeの値に応じて異なる挨拶を表示します。

クラス変数の値を変更することで、メソッドの動作も変わることが確認できます。

○サンプルコード7:動的なクラス変数の活用

クラス変数の真の力は、静的な値だけでなく、動的に値が変わる場面でもその効果を発揮します。

動的なクラス変数は、アプリケーションの状態や他の変数の値に応じて、自動的に値が変わるように設定されています。

Swiftでは、計算型のプロパティを使用して、このような動的なクラス変数を簡単に作成することができます。

ここでは、動的なクラス変数を活用したサンプルコードを紹介します。

class Shop {
    static var itemCount: Int = 0
    static var isShopOpen: Bool {
        return itemCount > 0
    }

    class func addItem() {
        itemCount += 1
    }

    class func removeItem() {
        if itemCount > 0 {
            itemCount -= 1
        }
    }
}

// アイテムを追加
Shop.addItem()
print(Shop.isShopOpen)  // trueが表示されます

// アイテムを削除
Shop.removeItem()
Shop.removeItem()
print(Shop.isShopOpen)  // falseが表示されます

このコードでは、ShopクラスにitemCountというクラス変数と、isShopOpenという計算型のクラス変数を持っています。

isShopOpenitemCountが0より大きい場合にtrueとなり、それ以外の場合はfalseとなるように設定されています。

addItemメソッドとremoveItemメソッドを使用してitemCountの値を動的に変更することができます。

そして、それに応じてisShopOpenの値も変動します。

このように、Swiftでは計算型のプロパティを利用して、動的なクラス変数を簡単に実装することができます。

この機能を活用することで、アプリケーションの状態や条件に応じた柔軟なコーディングが可能となります。

○サンプルコード8:クラス変数とプロパティオブザーバー

Swiftでは、プロパティオブザーバーという機能を使用して、変数の値が変更された時に特定の処理を実行することができます。

これはクラス変数にも適用することができ、変数の値の変更を監視して追加の処理を実行する場面で非常に役立ちます。

ここでは、プロパティオブザーバーを用いたクラス変数のサンプルコードを紹介します。

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

    class func addScore(score: Int) {
        totalScore += score
    }
}

// スコアを追加
ScoreManager.addScore(score: 50)
ScoreManager.addScore(score: 60)  // スコアが100を超えました!と表示されます

このコードでは、ScoreManagerクラスにtotalScoreというクラス変数があります。

このクラス変数には、didSetというプロパティオブザーバーが設定されており、totalScoreの値が変更されるたびに、その中の処理が実行されます。

この例では、totalScoreが100を超えた場合にメッセージが表示されるようになっています。

●クラス変数の注意点と対処法

Swiftでクラス変数を使用する際には、注意が必要な点がいくつか存在します。

これらの注意点を理解し、適切に対処することで、クラス変数を効果的に活用することができます。

ここでは、クラス変数を使用する際の主な注意点と、それぞれの対処法について詳しく解説します。

○サンプルコード9:スレッドセーフなクラス変数の取り扱い

マルチスレッド環境でクラス変数を扱う場合、同時に複数のスレッドからクラス変数へのアクセスが発生すると、データの不整合や不具合が生じる可能性があります。

このような状況を避けるためには、スレッドセーフなアクセスが求められます。

下記のサンプルコードでは、SwiftのDispatchSemaphoreを使用して、スレッドセーフにクラス変数を操作する方法を表しています。

import Foundation

class Counter {
    private static var _value: Int = 0
    private static let semaphore = DispatchSemaphore(value: 1)

    static var value: Int {
        get {
            semaphore.wait()
            let tempValue = _value
            semaphore.signal()
            return tempValue
        }
        set {
            semaphore.wait()
            _value = newValue
            semaphore.signal()
        }
    }
}

// 並列処理を行う場面での使用例
DispatchQueue.global().async {
    for _ in 1...100 {
        Counter.value += 1
    }
}
DispatchQueue.global().async {
    for _ in 1...100 {
        Counter.value -= 1
    }
}

このコードを実行すると、クラス変数valueへのアクセスはスレッドセーフとなり、複数のスレッドから同時にアクセスしても、データの不整合は発生しません。

○サンプルコード10:クラス変数のメモリ管理

Swiftのクラス変数は、プログラムの実行中は常にメモリに残ります。これはクラス変数が静的メモリ領域に確保されるためです。

しかし、大量のデータをクラス変数に保持すると、メモリの使用量が増加し、アプリケーションのパフォーマンスに悪影響を及ぼす可能性があります。

この問題を解決するための一つの方法は、weakunownedといった弱参照を使用して、クラス変数を定義することです。

class MyClass {
    var name: String?
}

class DataHolder {
    static weak var data: MyClass? = MyClass()
}

let object = DataHolder.data
print(object?.name)  // nilが表示されます

このコードでは、DataHolderクラスのdataクラス変数は、MyClass型のオブジェクトへの弱参照を保持しています。

そのため、他のオブジェクトから参照されなくなった場合、自動的にメモリから解放されます。

●クラス変数のカスタマイズ方法

Swiftにおけるクラス変数は柔軟性が高く、様々なカスタマイズが可能です。

ここでは、クラス変数を更に効果的に活用するためのカスタマイズ方法を、サンプルコードを交えて解説します。

○サンプルコード11:カスタムGetter/Setterの作成

クラス変数の値を取得する際や、新しい値を設定する際に独自の処理を加えたい場合があります。

Swiftでは、getsetを使用してカスタムのGetterやSetterを定義することができます。

例として、整数を格納するクラス変数で、取得時には必ず正の値として返す、また設定時には範囲制限をかけるというカスタマイズを考えます。

class CustomValue {
    private static var _value: Int = 0

    static var value: Int {
        get {
            // 必ず正の値を返す
            return abs(_value)
        }
        set {
            // 設定値が-10以上10以下の範囲に制限
            if newValue >= -10 && newValue <= 10 {
                _value = newValue
            }
        }
    }
}

CustomValue.value = 15
print(CustomValue.value)  // 0と表示される(15は設定の範囲外のため)

CustomValue.value = -5
print(CustomValue.value)  // 5と表示される(取得時に正の値として返される)

このコードを使って、CustomValueクラスのvalueクラス変数に15を設定しようとすると、設定の範囲外であるため変更は反映されません。

また、valueクラス変数に-5を設定しても、取得する際には正の値として5が返されます。

このように、GetterやSetterをカスタマイズすることで、クラス変数へのアクセスに特定のルールや制約を付けることができます。

まとめ

Swiftのクラス変数は、その特性とカスタマイズの幅広さから、さまざまなシーンでのアプリケーション開発において非常に有用な要素となっています。

この記事を通して、Swiftのクラス変数の基本から、その使い方、注意点、応用例、そしてカスタマイズ方法に至るまで、幅広い内容を解説しました。

特にカスタマイズの部分では、GetterやSetterを用いて、クラス変数の振る舞いを自在にコントロールする方法を解説しました。

これらのテクニックは、Swiftのクラス変数をより強力かつ効果的に活用するための鍵となります。

Swift初心者から中級者の方々が、この記事を参考にクラス変数の理解を深め、実際の開発現場での問題解決や機能実装に役立てていただければ幸いです。

日々の開発において、クラス変数の特性やカスタマイズ方法を駆使し、より質の高いアプリケーションの実現を目指してください。