Takahiro Octopress Blog

-1から始める情弱プログラミング

Swiftの基礎を理解しよう!(1)

Swiftを基本から覚えよう

さて、本日はSwiftについて基本から覚えていきたいと思います。
筆者はこれまでObjective-Cを中心に開発を続けてきました。
が、昨年Swiftが初めて発表されて以来、少しずつSwiftに関わることが増えてきました。
正直なところ、Xcodeのバージョンアップごとに『 割りと大きな変更が生じるSwift を商用アプリに使うかどうか』は迷います。deprecatedになるメソッドはあるにしても『 大幅な変更の生じないObjective-C 』の方が安全ですし、何より多彩なライブラリが存在しています。

とは言え、今後、Swiftしか使えないiOSアプリエンジニアが当たり前に存在していくことでしょう。
そんなときにObjective-CもSwiftも当然のように使えるエンジニアとなっていたいので勉強しておこうと思う次第です。

Swiftでプロジェクトを生成

言語でSwiftを選択してXcodeのプロジェクトを新規作成すると、ViewController.swiftは下記のように生成されます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import UIKit

class ViewController: UIViewController {
  
  override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
  }

  override func didReceiveMemoryWarning() {
      super.didReceiveMemoryWarning()
      // Dispose of any resources that can be recreated.
  }
}

これまでのObjective-Cでは下記のように生成されていました。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view, typically from a nib.
}

- (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
  // Dispose of any resources that can be recreated.
}

@end

少し違和感があるかもしれませんが、ぱっと見た感じ、あまり変わらないようにも見えます。
因みに、Objective-Cの場合はViewController.m, ViewController.hの2つのファイルが作成されますが、Swiftの場合は swift という拡張子のファイルのみです。

変数/定数の定義

Swiftでの変数/定数の定義の仕方を見て行きましょう。

1
2
3
4
5
6
7
8
9
10
class ViewController: UIViewController {
  
  override func viewDidLoad() {
      super.viewDidLoad()

      var variableString:String     // String型の変数を定義
      let invariableString:String       // String型の定数を定義
  }
  <省略>
}

【ポイント】

  • var 変数名:変数の型
  • let 定数名:定数の型
  • 1行の終わりは 改行 or ;(セミコロン)

letは 定数 なので、

1
2
3
4
let invariableString:String     // String型の定数を定義

invariableString = "これは定数です。"
invariableString = "定数なので、2回目以降の値設定はエラーが発生します。"

のようなことを書くと、invariableStringに対する2回目の値設定行で、
immutable value 'invariableString' may only be initialized onceエラーが発生します。
(varは定数なので問題ありません。)

グローバル変数/定数の定義

Swiftのグローバル変数/定数の仕方を見て行きましょう。

1
2
3
4
5
6
7
8
import UIKit

var globalVariableInt:Int = 3
let globalInvariableInt:Int = 5

class ViewController: UIViewController {
  <省略>
}

【ポイント】

  • クラス外に定義した変数/定数はグローバル変数/定数
  • グローバル変数/定数は共に初期値が必要

2つ目のポイントに書いた通り、初期値を与えないとGlobal 'var' declaration requires an initializer expression or getter/setter specifier, Global 'let' declaration requires an initializer expressionといったエラーが発生します。

オプショナル型と非オプショナル型

オプショナル型とは、Swiftで唯一『 nilの代入が許可された 』型です。逆に『 nilの代入を許可されていない 』型を非オプショナル型と言います。
では、Swiftのオプショナル型/非オプショナル型の仕方を見て行きましょう。

1
2
3
4
5
6
7
8
9
10
class ViewController: UIViewController {
  
  override func viewDidLoad() {
      super.viewDidLoad()

      var variableString:String?     // String型&オプショナル型の変数を定義
      let invariableString:String?   // String型&オプショナル型の定数を定義
  }
  <省略>
}

【ポイント】

  • var 変数名:変数型 ? でオプショナル型
  • let 定数名:定数型 ? でオプショナル型
  • オプショナル型の初期値は nil
  • 非オプショナル型の初期値は何も初期値が入っていない(nilが入っているわけではない)

これまで特に意識せずに変数/定数を定義してきたと思いますが、『 ? 』をつけていない変数/定数は自動的に非オプショナル型となります。
よって、

1
2
3
4
5
var variableString:String
let inVariableString:String

variableString = nil
inVariableString = nil

とするとCannnot assign a value of type 'nil' to a value of type 'String'とエラーが発生します。

因みに、 ? をつけた書き方は省略した書き方です。
var variableString:String?var variableString:Optional<String>と同じです。

オプショナル型の使い方(アンラップの仕方)

オプショナル型はそのままでは使えません。
例えば、var variableString:String?String型の変数をOptional(オプショナル)型の箱に入れているイメージです。
なので、String型として値を扱うためには『 Unwrap (アンラップ)』する必要があるのです。
(箱からString型を取り出すイメージです。)

アンラップには幾つか方法があります。

  • Forced Unwrapping
    強制的にアンラップする方法。変数/定数名の末尾に ! をつける
1
2
var fuga:String? = "FugaFuga"
println(fuga!.lowercaseString)

上記例でfuga.lowercaseStringとするとValue of optional type 'String' not unwrapped; did you mean to use '!' or '?'?という静的解析でエラーが発生します。
因みに、『 ! 』をつけた場合、中身がnilだと実行時にエラーが発生するので注意。

  • Optional Chaining
    Optionalのメソッドやプロパティ参照時にnilチェックする方法です。
    nilでなければUnwrapしてnilであった場合はnilを返す方法です。
    実はUnwrapして返されるものもOptional型であったりします。
    ただし、そのメソッドやプロパティを使うことができるのです。
1
2
3
4
5
6
7
var hoge:String?
var fuga:String? = hoge?.lowercaseString
println(fuga)

hoge = "HogeHoge"
fuga = hoge?lowercaseString
println(fuga)

上記を実行してみると、1回目のprintlnでnilが出力され、2回目のprintlnでOptional("hogehoge")と出力されます。

  • Optional Binding
    nilチェックをして、nilでない場合に限り、Unwrapして元の方を返す方法です。
    別名の変数/定数に値を入れ直して、以後、それを使っていく場合に使います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var hoge:String?

if var fuga:String = hoge {
  println("値が格納されていました。")
} else {
  println("nilでした。")
}

hoge = "HogeHoge"

if var fuga:String = hoge {
  println("値が格納されていました。")
} else {
  println("nilでした。")
}

上記の例文を実行すると、1回目はtrue, 2回目はfalseの条件分岐を通過するはずです。

  • Implicitly Unwrapped Optional
    使用時に自動的にUnwrapされて元の型が返される方法です。
    nilが入っているものに対して実行した場合はエラーが発生します。(静的解析時には判別されないことに注意)
1
2
3
4
5
vat hoge:String! = "HogeHoge"
println(hoge.lowercaseString)

var fuga:String!
println(fuga.lowercaseString)

上記の例文を実行すると、1回目のログは出力されますが、2回目のログ出力時にエラーが発生します。
因みに、『 型! 』は『 ImplicitlyUnwrappedOptional<型名> 』の省略形です。

1
2
var hoge:String! = "HogeHoge"
var fuga:ImplicitlyUnwrappedOptional<String> = "FugaFuga"

こんな感じですね。

オプショナル型の意義

前章でオプショナル型と非オプショナル型が存在することがわかりました。
では、このオプショナル型/非オプショナル型は何のために使うのでしょうか?

【オプショナル型/非オプショナル型を使う理由】

  • 静的解析でエラーを発見するため
  • 実行時の想定外のエラーを防ぐため
  • オープンソースとしてライブラリを作成した際に、ライブラリ利用者が想定外のエラーに合わないようにするため

クラスプロパティ

クラスプロパティの定義の仕方を見て行きましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
class ViewController: UIViewController {
  
  var variableNumber:Int?
  let unVariableNumber:Int = 3

  override func viewDidLoad() {
      super.viewDidLoad()

      var variableString:String     // String型の変数を定義
      let invariableString:String       // String型の定数を定義
  }
  <省略>
}

【ポイント】

  • クラスプロパティ定義時は初期値が必要
  • varは初期値がnilなので具体的な値を書く必要はない
  • letは初期値にnilが入らないので、具体的な値を設定する必要がある

クラスメソッド

クラスメソッドの定義の仕方を見て行きましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ViewController: UIViewController {
  
  var variableNumber:Int?
  let unVariableNumber:Int = 3

  override func viewDidLoad() {
      super.viewDidLoad()

      println(setTestString("abc", b:"def"))
  }

  <省略>

  func setTestString(a:String, b:String) -> String {
      return a+b
  }
}

【ポイント】

  • func メソッド名(第一引数名:第一引数の型, 第二引数名:第二引数の型, …) –> 戻り値の型 { …. }
  • 呼び出し側では、メソッド名(第一引数に渡す値, 第二引数名:第二引数に渡す値)

まだまだSwiftについて調べていきますが、記事が長くなってきたので本日はここまで。

参考サイト:

Comments