iTunes UにてDeveloping iOS 8 Apps with SwiftというStanford Universityの講義を発見したので、そちらを利用してswiftを学ぶことにしました。
xcodeの基本的な使い方から丁寧に説明されているのでオススメです。
※この記事はその備忘録です。あくまで備忘録なので、自分の中で残して置きたいと思ったものしか記載していません。
概要
Calculatorを実際に作りながら、swiftでアプリを作る方法を勉強していきます。
xcodeの使い方、MVCの考え方など基本的なところの説明もされているので、初心者でも勉強しやすい教材だと思います。
授業はもちろん英語で進みますが、字幕を使えばある程度理解できると思います。
xcodeの便利な使い方
optionを押しながら変数や関数名をクリックすると、変数の型や関数の引数などの情報が参照できる.
Auto Layout
Ctrl + Drag で2つのview間にconstraintsを設定できる.
- 黄色い線が今表示されているビューの位置
- 黄色い破線がconstraints(Auto-Layout)によって設定されるビューの位置
- 青い線が表示されているとき、今表示されている位置とconstraintsによって設定される位置が一致していることを示す→OKのサイン
- 赤い線がでるときはConstraints同士でコンフリクトするなどなんらかのエラーが出ている
黄色い破線が表示されているときの修正方法
document outlineの中の黄色い丸をクリック→修正する必要のあるところのリストが表示される.
修正したい項目の黄色い三角をクリック→修正方法を指定.
- Update Frame = 黄色い破線に合うようにビューを変更
- Update Constraints = 今表示されているビューになるようにConstraintを設定
- Reset to Suggested Contraints = 黄色い破線に合うようにConstraintを設定
Apply to all views in containerを選択しておくと全てのビューを一気に修正してくれる.
型について
swiftは型を推測してくれるので必ず書く必要はない.
var str = "string" // 自動的にString型になる
varは変更可能な変数、letは変更不可能な変数.
letを使うと絶対に変更されないことが保証されるので、コードを読むときに余計な心配が減る.(readable)
var varStr = "string"
varStr = "new string" // OK
let letStr = "string"
letStr = "new string" // NG
optional(?マーク)のついている変数が取りうる値は nil(not set) or something.
optionalをoptionalで無くしたいときは"!"でunwrapする.
let digit = sender.currentTitle // currentTitleはString? → digitもString?になる
let digit = sender.currentTitle! // unwrapしたのでdigitはString
もしunwrapしたときに変数がnilだったら、アプリはクラッシュする.
このことをうまく利用して、アプリをクラッシュさせることでリリース前にバグを発見することができる.
var tmp: String? = nil // optionalな変数にnilを代入
let str = tmp! // クラッシュ
!マークはoptionalだが、常に自動でunwrapしてくれるという意味の記号.
!マークだが依然としてoptinal型であることに注意.
optional型なのでもちろんnilを代入することができる
var display: UILabel?
let text = display!.text! // 毎回unwrapは面倒
var display2: UILabel!
let text = display2.text! // 自動でunwrapしてくれる
display2 = nil // OK
特殊文字
Edit>Special Charactersから√などの特殊文字を入力することができる.
(日本版だと、Edit>Emoji & Symbol)
Array, Dictionary
Array, Dictionaryは以下のように簡略化して書くことができる.
var array = Array<String>()
var array = [String]()
var dic = Dictionary<String, Double>()
var dic = [String:Double]()
代入時、呼び出し時に処理を追加したいとき
Calculatorでは、displayに表示されている文字列を数字として受け取りたい.
また、逆に数字をセットしたときにdisplayとなるUILabelのテキストを更新してほしい.
そういうときに以下の方法が使える.
var displayValue: Double {
get {
return NSNumberFormatter().numberFromString(display.text!)!.doubleValue
}
set {
display.text = "\(newValue)" // newValueは代入された値
}
}
関数を引数として渡すとき
馬鹿正直に書くと以下のようなコードになるとき、stackに入っている数字の確認や、計算後の更新作業など共通な部分がたくさんある.
switch operation {
case "×":
if stack.count > 2 {
result = stack.removeLast() * stack.removeLast()
updateDisplay(result)
}
case "÷":
if stack.count > 2 {
result = stack.removeLast() / stack.removeLast()
updateDisplay(result)
}
case "+":
if stack.count > 2 {
result = stack.removeLast() + stack.removeLast()
updateDisplay(result)
}
case "−":
if stack.count > 2 {
result = stack.removeLast() - stack.removeLast()
updateDisplay(result)
}
}
このとき、以下のような関数を使って処理を共通化することを考える.
func performOperation(operation: (Double, Double) -> Double){
if stack.count > 2 {
result = operation(stack.removeLast(), stack.removeLast())
}
}
performOperationは"Doubleの引数2つからDoubleを返す関数"を引数にとる関数.
これを使うと以下のように書ける.
multiplyという"2つのDoubleからDoubleを返す関数"を引数として渡していることがわかる.
func someFunction {
switch operation {
case "×": performOperation(multiply)
case "÷": ...
case "+": ...
case "−": ...
}
}
func multiply (op1: Double, op2: Double) -> Double {
return op1 * op2
}
この方法を使うときは他の場所でいちいち関数を宣言しなくても、その場で作成して渡すこともできる.
これをClosureと呼ぶ.
func someFunction {
switch operation {
case "×": performOperation({ (op1: Double, op2: Double) -> Double in // 引数の宣言
return op1 * op2 // 関数の中身
})
...
}
}
ここからはswiftの機能を利用して、この関数をよりシンプルにしていく.
はじめに、performOperationは"(Double, Double) -> Double"という関数を引数にとることがわかっているので、op1/2についているDoubleと返り値のDoubleは削除することができる.
また、Double型の値を返すことがわかっているので、returnも削除することができる
performOperation({ (op1, op2) in op1 * op2 })
次にswiftでは\$マークを利用して引数に名前をつけることなく利用することができる.
これを利用すると、引数を削除することができる.$マークを利用するときは0から始まることに注意.
また、関数が最後の引数のとき、関数を( )の外に出すことができる.
performOperation({ $0 * $1 })
performOperation(){ $0 * $1 } // 関数を( ) の外に出す
performOperation{ $0 * $1 } // ( )内に引数が無いので( )を削除
このようにすると最終的にswitch文の中は以下のようになる.
switch operation {
case "×": performOperation{ $0 * $1 }
case "÷": performOperation{ $1 / $0 }
case "+": performOperation{ $0 + $1 }
case "−": performOperation{ $1 - $0 }
}