この世でいちばんわかりやすいiPhoneアプリ開発のおはなし【型プロパティとは】
構造体について知っておくと、このページの理解が深まります。構造体については、こちらのページで説明しています。
型に備わるデータ
ハリウッドの映画やドラマを観ていると、マジックボールという玩具を目にすることがあります。 マジックボールは、問いかけながらボールをふると「何かしらの回答」が表示されるという占いのような玩具です。 大人になった主人公が物置部屋を整理していると、小さな頃に遊んだマジックボールが出てきて、久しぶりに悩み事を問いかけてみる...そんなシーンが多かったりします。 ここでは、そんなマジックボールをモデル化する構造体を考えます。
struct MagicBall {
}
マジックボールの回答文は、ボジティブなものからネガティブなものまで、製品によってさまざまな内容になっています。 ただし、イエスとノーは基本の回答文として、あらゆるマジックボールにも用意されています。
プロパティ値がすべてのインスタンスに共通する場合、staticキーワードを使って「型に備わるプロパティ」として定義できます。
struct MagicBall {
static let wards = ["Yes", "No"]
}
staticキーワードを使って定義した型に備わるプロパティを タイプ・プロパティ といいます。
タイプ・プロパティを参照するために、インスタンスを作成する必要はありません。 型自体から呼び出すことができます。
MagicBall.wards // ["Yes", "No"]
同様に、staticキーワードを使って、型に備わるメソッドを定義することができます。
struct MagicBall {
static let wards = ["Yes", "No"]
static func play() {
print(MagicBall.wards.randomElement()!)
}
}
上のコードは、MagicBall型自体から呼び出せるplay()メソッドの実装を示しています。 このような「型に備わるメソッド」を タイプ・メソッド といいます。
タイプ・メソッドもインスタンスを作成することなく、型自体から呼び出すことができます。
MagicBall.play() // Prints Yes or No.
タイプ・プロパティとタイプ・メソッドと区別するために、インスタンスに備わる通常のプロパティとメソッドを特に インスタンス・プロパティ 、インスタンス・メソッド と呼ぶことがあります。
マジックボールの回答文が2通りだけでは、遊んでいてもすぐに飽きてしまいます。 作成したインスタンスごとに、さまざまな回答文を追加して遊べるようにしましょう。
「追加の回答文」を保持するための変数プロパティを定義します。
struct MagicBall {
static let wards = ["Yes", "No"]
static func play() {
print(MagicBall.wards.randomElement()!)
}
var extraWards: [String]?
}
上のコードが示す通り、「追加の回答文」はオプショナル型なので、既定値としてnilが設定されます。 この変数extraWardsは、インスタンスごとに回答文を設定できるようにするためのインスタンス・プロパティです。
さっそく、インスタンスを作成して回答分を追加しましょう。 追加する回答文は、以下の5通りにします。
Without a doubt.(信じなさい)
Don’t count on it.(あてにするな)
Better not tell you now.(だまっておけ)
You may rely on it.(信じてもいい)
It is certain.(間違いない)
下のコードを実行すると、magic7ballの回答文は、Yes・Noと合わせて全部で7通りになります。
var magic7ball = MagicBall()
magic7ball.extraWards = ["Without a doubt.",
"Don't count on it.",
"Better not tell you now.",
"You may rely on it.",
"It is certain."]
次に、インスタンスから呼び出せるplay()メソッドを実装します。 タイプ・メソッドとインスタンス・メソッドは、互いに呼び出す対象が異なるので同じメソッド名を宣言できます。
struct MagicBall {
static let wards = ["Yes", "No"]
static func play() {
print(MagicBall.wards.randomElement()!)
}
var extraWards: [String]? = nil
func play() {
var availableWards = [String]()
if extraWards != nil {
availableWards = MagicBall.wards + extraWards!
} else {
availableWards = MagicBall.wards
}
print(availableWards.randomElement()!)
}
}
インスタンスのplay()メソッドでは、「基本の回答文」と「追加の回答文」を合わせた中から回答文を表示します。 ただし、「追加の回答文」がnilのままだった場合は、「基本の回答文」だけを表示対象にします。 上のコードは、このような条件分岐を行うIfステートメントで記述されたplay()メソッドを示しています。
三項演算子 を利用すると、これと同じロジックをより簡潔に記述できます。
struct MagicBall {
static let wards = ["Yes", "No"]
static func play() {
print(MagicBall.wards.randomElement()!)
}
var extraWards: [String]?
func play() {
let availableWards = extraWards != nil ? (MagicBall.wards + extraWards!) : MagicBall.wards
print(availableWards.randomElement()!)
}
}
インスタンスのplay()メソッドを呼び出して、より多彩な回答を返すマジックボールで遊べるようになりました。
magic7ball.play() // Prints seven different answers.
タイプ・プロパティは定数だけでなく、変数としても宣言できます。 あるいは、計算プロパティとしても宣言できます。
タイプ・メソッドは、インスタンス・メソッドと同様にパラメータを受け取ったり、値を返すことが可能です。
あわせて読もう
構造体には、型プロパティとして計算プロパティを定義することも可能です。計算プロパティについては、こちらのページで説明しています。