Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
46
Help us understand the problem. What are the problem?

More than 5 years have passed since last update.

posted at

updated at

Organization

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

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")
}
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
46
Help us understand the problem. What are the problem?