Swiftでは、クラスと構造体が同じようなことができる印象があります。
基本的にはクラスを使えばいいのでしょうが、
では、構造体はどんなときに使うんだというのが疑問になったので調べたメモになります。
比較表
クラス | 構造体 | |
---|---|---|
参照型/値型 | 参照型 | 値型 |
継承 | ◯ | × |
プロトコル実装 | ◯ | ◯ |
拡張 | ◯ | ◯ |
プロパティ(格納型) | ◯ | ◯ |
プロパティ(算出型) | ◯ | ◯ |
タイププロパティ(格納型) | × | ◯ |
タイププロパティ(算出型) | ◯ | ◯ |
メソッド | ◯ | ◯ |
タイプメソッド | ◯ | ◯ |
上記の中で特に意識すべきところは、
変数に入れるときに「参照型/値型」のどちらになるか。
クラスは、参照型なので、参照を渡すだけだが、
構造体は常にコピーを渡す。
構造体を使うパターン
- 小さくて単純なデータをカプセル化をしたい場合
- 参照渡しより値渡し(コピー)がいい場合
- 継承が必要ない場合
構造体を避けた方がいいパターン
- データが大きい
- プロパティが多い
理由としては、以下の2つ
- 構造体は変数にセットする度にコピーされるため、データが大きいと処理時間が遅くなる
- 構造体はスタック領域に確保されるため、データが大きいと溢れる可能性が高くなる
なので、APIやDBの取得データなどは構造体ではなく、クラスで作成したほうがよさそう
結論としては、
プロパティが数個のもので、カプセル化させると扱いやすいケース
メソッドはそのデータの加工を行うような場合に実装する
例えば・・・
イベントの開催日時と終了日時のデータをカプセル化しつつ、開催状態が分かるメソッドも用意する
イベント開催日時の構造体を作成
// イベント開催日時
struct EventDate {
var startDate : NSDate
var endDate : NSDate
// イベント開催状態
func state() -> EventState {
let now = NSDate();
let startCompareResult = now.compare(startDate)
let endCompareResult = now.compare(endDate)
// 開催日時と終了日時がどちらも未来の場合、開催前
if (startCompareResult == NSComparisonResult.OrderedAscending
&& endCompareResult == NSComparisonResult.OrderedAscending) {
return EventState.NotStart
}
// 開催日時と終了日時がどちらも過去の場合、イベント終了
else if (startCompareResult == NSComparisonResult.OrderedDescending
&& endCompareResult == NSComparisonResult.OrderedDescending) {
return EventState.Finish
}
// それ以外は、開催中
else {
return EventState.Now
}
}
}
実行結果
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "yyyy/MM/dd HH:mm"
var start = dateFormatter.dateFromString("2015/01/01 10:00")
var end = dateFormatter.dateFromString("2015/01/01 12:00")
var eventDate = EventDate(startDate: start!, endDate: end!)
var eventState = eventDate.state()
print(eventState.rawValue) // Finish
ちなみに、Swiftでのデータ型は構造体で作成されている
- String
- Array
- Dictionary
- Bool
- Int
- Double
- Float
などなど
なので、これらのものは、変数に入れる度にコピーされています。
こういうデータ型を自分で作成したい場合に構造体を使うといいんでしょうね。
さいごに
本当は、列挙型もメソッド定義ができるので、一緒にまとめたかったが、時間なくてできなかった。
時間ができたらここに追加します。