LoginSignup
45
44

More than 5 years have passed since last update.

Swiftに関するメモ その6 - メモリ管理と Optional Chaining

Last updated at Posted at 2014-06-11

https://developer.apple.com/swift/ より

The Swift Programming Language (iBooks Store)をざっくり目を通してつらつらと。

ARC (Autometic Reference Counting)

Swift では Objective-C で採用された ARC という仕組みでメモリ管理を行います。

ARC についてはざっくり……

  • 参照渡しのオブジェクトは strong が基本
  • 循環参照 (相互参照) になるオブジェクトに関しては weak
  • optional ではないオブジェクトに対して weak を利用したい場合は unowned
  • クロージャで参照されるオブジェクトはクロージャ内部で strong
  • なので、クロージャで self が循環参照になってしまうような場合にはクロージャ直前に [unowned self] と宣言してクロージャ内部で self を strong にならないようにする

Optional Chaining

任意型変数 (Optinal Value)

Swift では、変数や定数に対して任意型 (Optional) として宣言することができます。

var isEnabled: Bool? = true

型の後に続けて、? をつけると任意型になります。

Bool な変数は truefalse を取りますが、Bool? な変数はそれに加えて、値なし (No Value) な nil を取ります。

任意型な変数に対して初期値を設定しない場合、初期値は nil になります。

var isEnabled: Bool? // isEnabled は nil

また、任意型な変数を if などの条件式で検査した場合は nil かどうかを判断する挙動になることに注意。

例えば、次のようなコードを実行すると

var isEnabled: Bool? = false // isEnabled は false
if isEnabled {
  println("What!?") // 実行される
}

isEnabledfalsenil ではないので、if の条件式は「真」になり、"What!?" と出力されます。

この時に isEnabled の値そのもので条件式を実行したい場合、! をつけて任意形をアンラップ (unwrap) します。

var isEnabled: Bool? = false // isEnabled は false
if isEnabled! {
  println("What!?") // 実行されない
}

ただ、nil な値の変数をアンラップすると、実行時エラーとなるので注意。

var isEnabled: Bool? // isEnabled は nil
if isEnabled! { // エラー
  println("What!?")
}

Optinal Chaining

任意型の変数 (プロパティ) に ? をつけることで、次に続くプロパティやメソッドに値そのものを渡すように動作させることができます (暗黙的に ! がついたような動作になる)。

ただし、! と異なり、? は対象が nil の場合、それ以降の評価を止めるように動作し、実行時エラーにはなりません。

この動作の仕組みを利用してプロパティやメソッドを数珠つなぎのように呼び出すような記述をすることができます。これを Optinal Chaining と呼ぶようです。

例えば、

if let firstName = aPerson.info?.name?.firstName {
  println("first name is \(firstName)")
}

というコードでは、

  1. aPerson のプロパティ info に値が設定されていたら (nil ではなかったら)、
  2. info の中のプロパティ name にアクセスし、それが nil ではなかったら、
  3. name の中のプロパティ firstName にアクセスして、
  4. その内容をローカルな定数 firstName に格納します。

その結果、定数 firstName の値が if 文に対して評価されます。

したがって、以下のコードとほぼ同義です。

if aPerson.info {
  if aPerson.info!.name {
    let firstName = aPerson.info!.name!.firstName
    if firstName {
      println("first name is \(firstName)")
    }
  }
}

動作サンプル:

struct Address {
  var street:String?
  var postalCode:String?
}
struct Name {
  var firstName:String?
  var lastName:String?
}
struct Info {
  var name:Name?
  var address:Address?
}
class SomeClass {
  var info:Info?
  init(info:Info?) {
    self.info = info
  }
}
let name = Name(firstName:"Steve", lastName:"Jobs")
let address = Address(street:"1 Infinite Loop", postalCode:nil)
var aPerson = SomeClass(info:Info(name:name, address:address))
if let firstName = aPerson.info?.name?.firstName {
  println("first name is \(firstName)")
} else {
  println("No first name")
}
45
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
44