Swift実践入門 ~ 今からはじめるiOSアプリ開発! 基本文法を押さえて、簡単な電卓を作ってみよう

初めてSwiftを触るエンジニアの方向けに、Swiftの基本から、実際に動くiOSアプリ開発までを解説します。実際に手を動かして覚える内容となっているので、Xcodeを操作しながら読み進んでください。

Swift実践入門 ~ 今からはじめるiOSアプリ開発! 基本文法を押さえて、簡単な電卓を作ってみよう

はじめまして、山野貴史と申します。Webアプリケーション開発やiOSアプリの制作等を行っています。

好物はRubyと、Rails。RailsAmpという、AMP(Accelerated Mobile Pages) に対応するRuby on Railsのプラグインgemを作りました。エディタはVim派です。Swiftも大好きです。

本稿では、初めてSwiftを触るエンジニアの方向けに、Swiftの基本から、実際に動くiOSアプリ開発までを解説します。Swiftを対話的に動作させて慣れた後、簡単な電卓アプリを制作してみます。

SwiftのサンプルコードやXcodeのスクリーンショットを豊富に掲載し、手を動かして覚える内容となっています。読者の皆様自身がXcodeの操作を通じて、実際の動作を確認しながら読み進んでいただけると嬉しく思います!

Swiftの特徴

Swiftは、Apple社のiOSやmacOSのアプリケーション開発に用いられるプログラミング言語です。本稿の執筆時点で、最新バージョンはSwift 3.1です。

Swiftの主な特徴は以下の2点です。

静的型付け
プログラム実行前の段階(コンパイル時)に、変数や定数の型情報を決定する。実行時エラーを事前に発見できる
型推論
変数や型を宣言しなくても、変数の型が自動的に決定される。記述が簡潔になる

また、Swiftはオブジェクト指向や関数型言語の特徴を持っています。WebエンジニアでRubyやPython等の経験があれば、Swiftの習得も早いはずです。オブジェクト指向やクロージャの概念が、Swift開発でも役に立ちます!

型付け 処理系 IDE/エディタ 主な開発分野
Swift 静的 コンパイラ Xcode iOS、macOS、tvOS
Java 静的 コンパイラ Eclipse、NetBeans、IntelliJ IDEA、Android Studio等 Webサーバーサイド、Android、各種OS・組み込みシステム等幅広い
Ruby 動的 インタプリタ(JRuby等の処理系ではコンパイラ可) Vim、Emacs、Atom、RubyMine等 Webサーバーサイド(Ruby on Rails)
Python 動的 インタプリタ Vim、Emacs、Atom、PyCharm等 Webサーバーサイド、機械学習、統計分析等

ひとつ注意点ですが、Swiftは書き方の自由度が比較的高いので、チーム開発をする場合は、あらかじめコーディング規約を共有しておいた方が良いでしょう。

Swiftでの命名や慣例のほか、さまざまな指針がSwift.orgにある「API Design Guidelines」にまとめられています。興味のある方は目を通してみてください。

1Swift.org - API Design Guidelines2

インタラクティブ環境でSwiftを触ってみよう

早速ですが、Swiftを触って動作させてみましょう。Swiftはコンパイラ言語でありながら、インタラクティブ(対話的)に実行しながら動作を確認することができます。Swiftに慣れるには、このインタラクティブ環境でいろいろと動作させてみるのが手っ取り早いです。

インタラクティブにSwiftを実行するには、ターミナル(コマンドライン)のREPL(レプル)を使う方法と、XcodeのPlaygroundを使う方法の2つがあります。

動作確認の環境

本記事中で、サンプルコードの動作確認を行った環境のバージョン情報です。

  • MacOS Sierra 10.12.4
  • Swift 3.1
  • Xcode 8.3.2
  • CocoaPods 1.2.1
  • Expression 0.5.0(CocoaPodsライブラリ)
  • iOSシミュレーター iPhone 7&iOS 10.3

Swift、Xcodeのバージョンは、以下コマンドで確認できます。

$ swift --version
Apple Swift version 3.1 (swiftlang-802.0.53 clang-802.0.42)
Target: x86_64-apple-macosx10.9

$ xcodebuild -version
Xcode 8.3.2
Build version 8E2002

それでは、Swiftの実践へと移ります!

実行方法1. ターミナルのREPL

REPLとは、Read-Eval-Print-Loop(対話型実行環境)のことです。Swiftは、ターミナルからREPLを起動できます。

$ swift
Welcome to Apple Swift version 3.1 ...
  1> print("hello world")
hello world
  2> 1 + 1
$R0: Int = 2
  3> :exit
$

ターミナルでswiftと入力すると、矢印が表示され、入力待ちの状態となります。Swiftのコードを書いて、returnキーを押します。Swiftコードが実行され、コードが評価された結果が次の行に出力されます。REPLは、:exitで終了できます。

実行方法2. XcodeのPlayground

Xcodeは、エディタのほか、デバッガやGUIデザイナ等の機能を備えた、SwiftのIDE(統合開発環境)です。XcodeのPlaygroundを使うと、Swiftを対話的に実行できます。 通常、SwiftでのiOSアプリ開発にはXcodeを使い、ビルドして実行します。

Xcodeは、Mac App Storeからインストールしましょう。

Xcode - Apple Developer4

Xcodeを起動して、「Get started with a playground」を選択します。

5

または、Xcodeのメニューから[File]→[New]→[Playground...]を選択します。

6

ターミナルのREPLと同様に、PlaygroundでもSwiftを対話的に実行できます。Playground上で実行したコードが保存できますので、対話的に書いたコードを後で見直したい場合にも便利です。

Vimmerならプラグイン「XVim」をインストールしよう

唐突ですが、読者の皆さんはVim好きですか? 私はVimが大好きです! RubyやRails等でコードを書くときはもちろん、この記事執筆にも、いつでもどこでもVimを使っています。

Vim使いの方であれば、当然「XcodeもVimのキーバインドで使いたい」って考えますよね。そんなVimmer達の願いをかなえてくれるのが、XVimというXcodeの神プラグインです。Vim好きな方は、iOS開発に取り組む前に、ぜひXVimをインストールしてみてください。

github.com

Xcode 8の場合は、XVimインストールの前に、あらかじめXVimプラグイン用の証明書を作成しておく必要があります。証明書の作成方法は次のドキュメントをご参照ください。

7Install XVim for Xcode 8 - XVimProject/XVim

証明書を作成した後は、以下の手順でXVimをインストールします。

$ cd ~/Library/Application\ Support/Xcode
$ mkdir plugins
$ cd plugins
$ git clone https://github.com/XVimProject/XVim
$ cd XVim
$ make
...
 ** BUILD SUCCEEDED **

XVimは、Playgroundでも動作します。Vimmerな方はあらかじめインストールしておくと、Playground上でコードを書いて試すのが断然速くなります。

Emacsのキーバインド

XcodeをEmacsのキーバインドで使いたい場合、本稿執筆現在ではKarabiner正式版の最新バージョンがmacOS Sierraに対応していないため、代替としてHammerspoonを使うと良いようです。

Swiftの基本文法(1)変数、配列、ディクショナリの定義、制御構造

アプリ制作に入る前に、Swiftの基本的な文法を確認していきます。

Swiftの基本的な文法は、CやC++、Objective-C、Java、Ruby、Python、JavaScript等のプログラミング言語を一つでも知っている方であれば、比較的なじみやすいでしょう。

Swiftには、BoolIntFloatDoubleCharacterStringArrayDictionary等の基本的な型に加えて、nil(他言語ではnullとも呼ばれる)を許容するOptionalという型が存在します。Swiftの特徴であるOptional型や、それを扱うOptional Bindingと呼ばれる機能については、初見ですとちょっと難しいので後述します。

本稿のサンプルコードは、先述したターミナルのREPLか、XcodeのPlaygroundで試しながら読み進めると理解しやすいかと思います。

変数の定義

まずは変数の定義です。変数の定義にはletvarを使います。

// letでイミュータブルな変数(1行コメント)
let immutableStr = "hello"
immutableStr += " world"  // => error

/*
 * varでミュータブルな変数
 * (複数行コメント)
 */
var mutableStr = "hello"
mutableStr += " world"
print(mutableStr)  // => hello world

※イミュータブル……作成後に状態を変えられないオブジェクトのこと。対義語はミュータブル

上の例では、型推論により、変数の型はString型となります。明示的に型を指定するには、以下のように書きます。

var mutableStr: String = "hello"

Swiftでは 暗黙の型変換は行われません。よって、型を変換したい場合は、明示的に記述する必要があります。

let label = "This year is "
let year = 2017
let thisYear = label + String(2017)
print(thisYear)  // => This year is 2017
// 文字列内での変数展開
let nextYear = "Next year is \(year + 1)"
print(nextYear)  // => Next year is 2018

配列の定義

配列(Array型)は次のように定義します。

var itemsArray = ["foo", "bar", "baz"]
// 型を明示
var itemsArray: [String] = ["foo", "bar", "baz"]

ディクショナリの定義

ディクショナリ(Dictionary型)は、["キー": "値"]のように記します。

var itemsDictionary = [
  "foo": "FOO",
  "bar": "BAR",
  "baz": "BAZ"
]

// 型を明示
var itemsDictionary: [String: String] = [
  "foo": "FOO",
  "bar": "BAR",
  "baz": "BAZ"
]

制御構造

forループや、ifelseによる制御は次のように記述します。

let list = [3, 7, 9, 12, 8, 5]
for number in list {
  if number % 2 == 0 {
    print("number \(number) is even")
  } else {
    print("number \(number) is odd")
  }
}

whileループです。

var number = 1
while number < 10 {
  print(number)
  number += 1
}

switchcaseです。

let age = 17
switch age {
case 0...6:
  print("kindergarden kid")
case 7...12:
  print("primary school student")
case 13...15:
  print("junior high school student")
case 16...18:
  print("high school student")
case 19...22:
  print("college student")
default:
  print("business person")
}
// => high school student

Swiftでは、RubyのようなRangeオブジェクトを使うことができ、さらにswitchcaseでは、数値がRangeオブジェクトの範囲に入るかどうかを良い感じに判定してくれます。

ここまではC言語由来のプログラミング言語の文法に似ていますので、分かりやすいです。

Swiftの基本文法(2)関数、クロージャ、クラス定義・オブジェクト

関数(メソッド)

関数(メソッド)定義の書き方です。

func greet(expression: String, person: String) -> String {
  return "\(expression) \(person)."
}

greet(expression: "Hello", person: "Mike")  // => "Hello Mike."

以下の書き方が、関数定義の基本になります。

func 関数名(引数1: 引数1の型, 引数2: 引数2の型, ...) -> 返り値の型 {
}

関数を呼び出すときは、名前付き引数として(引数ラベル: 引数の値...)のように渡します。

関数定義で引数ラベルを明示する場合は、以下のように書きます。アンダースコアを使うと、関数呼出し時に名前付き引数のラベルを省略できます。

func greet(_ expression: String, to person: String) -> String {
  return "\(expression) \(person)."
}

greet("Hello", to: "Mike")  // => "Hello Mike."

なお、Swiftでは関数のシグネチャの書き方が多種多様です。見慣れない書き方があった場合は、その都度チェックしてみてください。

クロージャ

続いて、Swiftでのクロージャの例を見てみましょう。JavaScript等で同様の例をご存知の方も多いのではないでしょうか。

func incrementer() -> ( () -> Int ) {
  var count = 0
  func increment() -> Int {
    count += 1
    return count
  }
  return increment
}

var counter = incrementer()
counter()  // => 1
counter()  // => 2
counter()  // => 3

returnされる関数を無名関数にしてみます。

func incrementerWithAnonymousFunc() -> ( () -> Int ) {
  var count = 0
  return { () -> Int in
    count += 1
    return count
  }
}

var counter2 = incrementerWithAnonymousFunc()
counter2()  // => 1
counter2()  // => 2
counter2()  // => 3

関数は、引数として関数を受け取ることができます。

func numbersMap(list: [Int], condition: (Int) -> Int) -> [Int] {
  var numbers: [Int] = []
  for item in list {
    numbers.append( condition(item) )
  }
  return numbers
}

var items: [Int] = [1, 2, 3, 4, 5]
numbersMap(list: items, condition: { (number: Int) -> Int in number * 2 })  // => [2, 4, 6, 8, 10]

このクロージャ機能により、Swiftではmapfilterreduce等のメソッドに、引数として無名関数のブロックコードを渡して処理することができます。

var numbers = [3, 7, 9, 12, 8, 5]
// 配列の要素をすべて2倍にする
numbers.map({ (number: Int) -> Int in return number * 2 })  // => [6, 14, 18, 24, 16, 10]

// 奇数のみを抽出する
numbers.filter({ (number: Int) -> Bool in return number % 2 == 1 })  // => [3, 7, 9, 5]

// すべての合計を計算する
numbers.reduce(0, { (total: Int, number: Int) -> Int in
  return total + number
})  // => 44

さらに、mapfilterreduceの引数でブロックコードを渡す場合は、型指定を省略した書き方が可能です。

numbers.map{ number in number * 2 }  // => [6, 14, 18, 24, 16, 10]
numbers.filter{ number in number % 2 == 1 }  // => [3, 7, 9, 5]
numbers.reduce(0){ total, number in total + number }  // => 44

まるでRubyのコードのようですね。Rubyのブロック引数の||inに変わっただけで、とてもよく似ています。SwiftがRubyに影響を受けたことを伺わせるシンタックスです。

クラス定義とオブジェクト

次は、クラス定義とオブジェクト作成のコード例です。他言語と似たような書き方ですので、分かりやすいかと思います。

class MyApp {
  // Shapeクラスの定義
  class Shape {
    // nameプロパティ(インスタンス変数)
    var name: String

    // イニシャライザ(コンストラクタ)
    init(name: String) {
      self.name = name
    }
  }

  // 四角形: RectangleがShapeを継承
  class Rectangle: Shape {
    var width: Double
    var height: Double

    init(name: String, width: Double, height: Double) {
      self.width = width
      self.height = height
      // 親クラスのイニシャライザ呼び出し
      super.init(name: name)
    }

    func area() -> Double {
      return width * height
    }
  }

  // 三角形: TriangleがShapeを継承
  class Triangle: Shape {
    var bottom: Double
    var height: Double

    init(name: String, bottom: Double, height: Double) {
      self.bottom = bottom
      self.height = height
      super.init(name: name)
    }

    func area() -> Double {
      return bottom * height / 2.0
    }
  }
}

// 正方形を作成
var square = MyApp.Rectangle(name: "My Square", width: 7.5, height: 7.5)
square.name    // => "My Square"
square.area()  // => 56.25

// 三角形を作成
var triangle = MyApp.Triangle(name: "My Triangle", bottom: 10, height: 8)
triangle.name    // => "My Triangle"
triangle.area()  // => 40

そのほか、Swiftでは、enum(列挙型)struct(構造体)protocol(インターフェース)extension(クラス拡張、モンキーパッチ)generics(ジェネリクス)機能も利用できます。ここで詳しくは触れませんが、興味がある方はドキュメント等を参照してください。

Swiftの基本文法(3)Optional型

Swiftの言語仕様の特徴として、nilを安全に扱うためにOptionalという型が存在します。

そのため、Swiftでnilを許容する変数は、Optional型として定義する必要があります。変数をOptional型で定義しない限り、変数にnilを代入することはできません。非Optional型の変数、たとえば通常のInt型やString型の変数には、nilを代入できません。

Optional型を使うことで、変数やメソッドの戻り値がnilになり得ることを、プログラマが明示できます。不適切にnilの可能性のある変数にアクセスするコードを書いていた場合、コンパイル時に警告が出て、nilが返ることによる予期せぬ実行時エラーの発生を防ぐ働きをしてくれるわけです。

Ruby/Railsでは、次の例のようにメソッド呼び出しやメソッドチェインの途中でnilが返ってしまい、NoMethodErrorの実行時エラーが発生した経験はないでしょうか?

user.name                   # userがnilの場合NoMethodErrorになる
user.name if user.present?  # ifでチェックしuserが存在する場合のみ実行
user&.name                  # safe navigation operator -> userがnilの場合nilを返す
user.try(:name)             # RailsのObject#try -> userがnilの場合nilを返す

Ruby/Railsの場合、変数のnilチェックやnilアクセスに対する適切な処理は、プログラマのコーディングに委ねられています。上記の例のように、ifnilチェックしたり、tryメソッドやsafe navigation operator(通称ぼっち演算子&.を使うといった処理を、プログラマが責任を持って行う必要があります。

一方、Swiftでは、nilになり得る変数を使う場合のために、言語仕様自体にnilを安全に扱えるようにするOptional型という仕組みが組み込まれています。

また、SwiftでOptional型を扱う際には、さまざまな文脈で?(クエスチョンマーク)!(エクスクラメーションマーク)が登場します。Rubyを使われる方は、Rubyでは真偽値を返すメソッドに?が付いたり、破壊的メソッドに!が付くことをご存知かと思いますが、Swiftではまったく概念が異なりますので、その点は注意してください。

Optional型の実際のコードを見ていきましょう。

Optional型の変数を定義

// Optional Int
var optionalInt: Int? = 5
// 通常のInt
var int: Int = 5

// Optional String
var optionalStr: String? = "hello"
// 通常のString
var str: String = "hello"

// Optional Stringの変数にnilを代入
optionalStr = nil
// 通常のStringにはnilを代入できない
str = nil  // => error: nil cannot be assigned to type 'String'

Int?nilまたはInt型の値を代入できる型、String?nilまたはString型の値を代入できる型です。Int?Intはまったく別の型であり、同様にString?Stringもまったく別の型です。

このT?という書き方は、Optional<T>のシンタックスシュガーですので、以下のようにも書けます。

var optionalInt: Optional<Int> = 5
var optionalStr: Optional<String> = "hello"

Swiftの基本文法(4)Optional型をアンラップする4つの方法

エンジニアHubに会員登録すると
続きをお読みいただけます(無料)。
登録のメリット
  • すべての過去記事を読める
  • 過去のウェビナー動画を
    視聴できる
  • 企業やエージェントから
    スカウトが届く