このページは「はじめてのSwiftプログラミング」(清水美樹著、工学社刊、2014年8月23日発売、ISBN978-4-7775-1851-7)の著者によるサポートページです
Swiftでは、プロパティを「オプショナル型」にしておけば、インスタンスの作成時には定義しなくて構いません。 そのかわり、プロパティをずっとオプショナル値として扱わなければならないので、コーディングがめんどくさくなります。
「インスタンスの作成時にいちいちプロパティを設定したくないけれど、 実際使うときには必ず設定するんだから」・・・ そんなめんどくさがりやさんのプログラミングには「強制アンラップ」が便利です。
オプショナル型のプロパティについては、同じサイトの「Nilかも知れないプロパティ」
で説明しました。
すなわち、クラスの定義において、プロパティには初期値を与えておくかinitメソッドの引数としてインスタンスの作成時に決めるか、
どちらもイヤなら、オプショナル型にしておきます。
その「「Nilかも知れないプロパティ」」と似たようなプログラムで解説しましょう。
すなわち、リスト1は、あるギター奏者がコンサートツアーに出かけることを想定したクラスTourの定義です。
class Tour{ let name:String var bass:Musician? var drums:Musician? var message = "" init(name:String){ self.name = name message = "やあ、今度、\(self.name)に行くよ!\n" } }
上のリスト1で、クラスTourに定義されあt二つのvar型プロパティbass及び drumsは、
ツアーに同行してくれるベースとドラム奏者を表します。
ただし、「ツアー」が決まっても、まだギター奏者本人以外のメンバーは決まっていないこともあるので、
「オプショナル型」になっています。
いずれのプロパティも、値があるとしたら下のリスト2に示すクラスMusicianのインスタンスです。
class Musician{ let name:String var part:String init(name:String, part:String){ self.name = name self.part = part } }
このようにして、クラスTourの定義においてオプショナル型のプロパティを定義しました。
これらのプロパティを用いるために、クラスTourの定義に加筆します。
リスト2に示すメソッドaddBase及びaddDrumsを見てください。
プロパティbass及びdrumsを強制アンラップした形で、値を取り出しています。
func addBase(musician:Musician){ bass = musician message += "ベースは\(bass!.name)、最高だぜ!\n" } func addDrums(musician:Musician){ drums = musician message += "ドラムは\(drums!.name)、ヤツはクレイジーだ!\n" }
もしリスト2をアンラップしないでリスト3のように書くと、エラーになります。
message += "ベースは\(bass.name)、最高だぜ!\n"
一方、もしリスト2をオプショナル型のまま、リスト4のように書くと、 エラーにはなりませんが、値を取り出せず妙な結果になります。
message += "ベースは\(bass?.name)、最高だぜ!\n"
たとえば図1は、messageの内容をPlaygroundで出力した結果ですが、 「オプショナルなインスタンス」として無理矢理文字列が表示されています。
これに対して、プロパティをアンラップの形で定義することもできます。以下に説明しましょう。
もし、このツアーに必ずベースとドラムの奏者を加えるとわかっている場合は、 プロパティbass及びdrumのほうを強制アンラップで定義する方法もあります。
すなわち、クラスTourの定義において、bass及びdrumの定義をリスト5のように書きます。
var bass:Musician! var drums:Musician!
リスト5のようにアンラップすると、そのあと、オプショナルでない型のように扱える利点があります。
たとえば、リスト6は、リスト2と同じメソッドaddBaseですが、アンラップしなくてよくなりました。
func addBase(musician:Musician){ bass = musician message += "ベースは\(bass.name)、最高だぜ!\n" }
ここで疑問が出てきます。
プロパティbassの型は、「Musician!」です。でも、メソッドaddBaseの引数は「Musician」です。
両者をそろえるためにリスト7のようにしたらいいと思いませんか?でも、実はエラーになります。
func addBass(musician:Musician){ bass = musician! }
この理由は、引数の型が「Musician」だからです。これは「オプショナル型」ではありませんから強制アンラップが「できません」。
「Musician!」とはもとが「Musician?」だからこそ「!」がついているのです。
ゆえに、リスト8なら正しい結果になります。 引数musicianが「Musician?」型でその強制アンラップ型をbassに割り当てるからです・・・ でも、わざわざこのようにする意味はありませんね。
func addBass(musician:Musician?){ bass = musician! }
また、引数の型を「Musician!」にしても正しい結果が得られます。これも意味はありませんが・・・
func addBass(musician:Musician!){ bass = musician }
強制アンラップ型の最も顕著な使用例は、iOSの部品(IBOutlet)プロパティです。 このページはその説明のために書いたようなものです。