Swift のクラス定義

Swift でのクラス定義のやり方をご紹介します。(※ Swift4の仕様にもとづきます)

インスタンス変数・インスタンスメソッド

基本的な書き方は以下のようになります。

class User {
    var name: String
    
    // コンストラクタ(初期化時に呼ばれます)
    init(name: String) {
        self.name = name // 引数の変数名とクラスのプロパティを区別するため、selfをつけます
    }

    func hello() {
        print("Hello, \(self.name)")
    }
}

let user: User = User(name: "Tanaka")
user.hello() // "Hello, Tanaka"

Swift のインスタンス変数は、?! で Optional かそうではないかを指定しない場合、必ず値を格納するStored Property(格納型プロパティ)と、値を保持せず、getter/setter などを通して他のプロパティに値をセットしたり返したりするComputed Property(計算型プロパティ)のどちらかの形式をとることになります。

Stored Property

初期化時に値がセットされている必要があります。値をセットしないとエラーになります。

class User {
    var name: String
    var age: Int = 20
    
    init(name: String) {
        self.name = name
    }
}

Computed Property

getter/setterを使用します。

class Product {
    var price: Double {
        get {
            return priceWithTax / 1.08
        }
        set {
            print(newValue) // newValue でセットされた値を参照できます
            self.priceWithTax = newValue * 1.08
        }
    }
    var priceWithTax: Double = 0
}

let product = Product()
product.price = 100
print(product.priceWithTax) // 108.0

getter/setter は、上記のようにプロパティにネストする形で書きます。ここがややこしいのですが、Swift では他の言語のように自身のプロパティの値をセットしたり取得したりするのではなく、他のプロパティの値を操作するために使用します。

また、setter は単独で使うことはできず、必ず getter とセットで定義します。getter は
setter がなくても定義できます。また、get {} を省略し、return 値で表すこともできます。

class User {
    var name: String {
      return "Tanaka"
    }
}

willSet と didSet

setter の他にも、値をセットする直前・直後にwillSet/didSet が呼ばれます。didSet は自身のプロパティを操作することも可能です。

class User {
    var name: String = "" {
        willSet {
            print(newValue) // newValue でセットされようとしている値を参照できます
        }
        didSet {
            print(oldValue) // oldValue でセット前の値を参照できます
        }
    }
}

let user = User()
user.name = "Tanaka"

didSet 内で自身のプロパティに値をセットしても、再度 didSet が呼ばれることはありません。この2つは setter と一緒には使えないので注意しましょう。

クラス変数・クラスメソッド

変数・クラスの前に class または static をつけます。

class Greeting {
    class var greeting: String {
        return "Good morning, everyone"
    }
    static var greeting2: String = "Hello, everyone"
    
    class func morning() {
        print(self.greeting)
    }
    
    static func noon() {
        print(self.greeting2)
    }
}

Greeting.morning() // "Good morning, everyone"
Greeting.noon() // "Hello, everyone"

class と static の違いは以下のとおりです。

オーバーライド Struct/Enum Stored Property
static
class

アクセス修飾子

Swift には以下の5つの修飾子があります。

修飾子 説明
open 別のモジュールからもアクセスできる
public 別のモジュールからもアクセスできるが、
別モジュールでは継承、オーバーライドできない
internal モジュール内ならアクセスできる(デフォルト値)
fileprivate 同じファイル内ならアクセスできる
private 同じクラス内ならアクセスできる

変数で使用する場合は var/let の前、メソッドで使用する場合は func の前につけます。