このページは「はじめてのSwiftプログラミング」(清水美樹著、工学社刊、2014年8月23日発売、ISBN978-4-7775-1851-7)の著者によるサポートページです

目次へ

このサイトのトップへ

強制アンラップ

 

Swiftでは、プロパティを「オプショナル型」にしておけば、インスタンスの作成時には定義しなくて構いません。 そのかわり、プロパティをずっとオプショナル値として扱わなければならないので、コーディングがめんどくさくなります。

「インスタンスの作成時にいちいちプロパティを設定したくないけれど、  実際使うときには必ず設定するんだから」・・・ そんなめんどくさがりやさんのプログラミングには「強制アンラップ」が便利です。

「オプショナル型」で定義する場合

プロパティをあとで決める

オプショナル型のプロパティについては、同じサイトの「Nilかも知れないプロパティ」 で説明しました。
すなわち、クラスの定義において、プロパティには初期値を与えておくかinitメソッドの引数としてインスタンスの作成時に決めるか、 どちらもイヤなら、オプショナル型にしておきます。


オプショナル型のプロパティを持つクラスの定義

その「「Nilかも知れないプロパティ」」と似たようなプログラムで解説しましょう。
すなわち、リスト1は、あるギター奏者がコンサートツアーに出かけることを想定したクラスTourの定義です。

リスト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のインスタンスです。

リスト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を強制アンラップした形で、値を取り出しています。

リスト2 強制アンラップして使う
func addBase(musician:Musician){
        bass = musician
        message += "ベースは\(bass!.name)、最高だぜ!\n"
    }

    func addDrums(musician:Musician){
        drums = musician
        message += "ドラムは\(drums!.name)、ヤツはクレイジーだ!\n"
    }

アンラップしないとエラー

もしリスト2をアンラップしないでリスト3のように書くと、エラーになります。

リスト3 アンラップしないとエラー
message += "ベースは\(bass.name)、最高だぜ!\n"

オプショナルのままだと意図しない結果に

一方、もしリスト2をオプショナル型のまま、リスト4のように書くと、 エラーにはなりませんが、値を取り出せず妙な結果になります。

リスト4 オプショナル型のままだと、エラーにはならないが・・・
message += "ベースは\(bass?.name)、最高だぜ!\n"

たとえば図1は、messageの内容をPlaygroundで出力した結果ですが、 「オプショナルなインスタンス」として無理矢理文字列が表示されています。

図1 リスト4のように書いたときの出力結果

これに対して、プロパティをアンラップの形で定義することもできます。以下に説明しましょう。

プロパティをアンラップとして定義

必ず値を与えるとわかっている場合

もし、このツアーに必ずベースとドラムの奏者を加えるとわかっている場合は、 プロパティbass及びdrumのほうを強制アンラップで定義する方法もあります。

すなわち、クラスTourの定義において、bass及びdrumの定義をリスト5のように書きます。

リスト5 プロパティの型をアンラップ
var bass:Musician!
var drums:Musician!

アンラップすると何がいいのか

リスト5のようにアンラップすると、そのあと、オプショナルでない型のように扱える利点があります。

たとえば、リスト6は、リスト2と同じメソッドaddBaseですが、アンラップしなくてよくなりました。

リスト6 メソッドaddBaseの改良版
func addBase(musician:Musician){
    bass = musician
    message += "ベースは\(bass.name)、最高だぜ!\n"
}

Musician!じゃないのか?

ここで疑問が出てきます。

プロパティbassの型は、「Musician!」です。でも、メソッドaddBaseの引数は「Musician」です。
両者をそろえるためにリスト7のようにしたらいいと思いませんか?でも、実はエラーになります。

リスト7 !がついてよさそうだがエラー
func addBass(musician:Musician){
  bass = musician!
 }

この理由は、引数の型が「Musician」だからです。これは「オプショナル型」ではありませんから強制アンラップが「できません」。

「Musician!」とはもとが「Musician?」だからこそ「!」がついているのです。

ゆえに、リスト8なら正しい結果になります。 引数musicianが「Musician?」型でその強制アンラップ型をbassに割り当てるからです・・・ でも、わざわざこのようにする意味はありませんね。

リスト8 正しい。意味はないが。
func addBass(musician:Musician?){
  bass = musician!
}

また、引数の型を「Musician!」にしても正しい結果が得られます。これも意味はありませんが・・・

リスト9 これも正しいが、意味もない
func addBass(musician:Musician!){
  bass = musician
}

強制アンラップ型のプロパティの使用例

強制アンラップ型の最も顕著な使用例は、iOSの部品(IBOutlet)プロパティです。 このページはその説明のために書いたようなものです。

図2 IBOutletのプロパティは全てアンラップ型になる

目次へ

このサイトのトップへ