Swiftの序の序(文法編)

# はじめに
超絶Swift入門向けの記事です。
Swiftってif文とかforループとか型定義とかどうやって書くの？ってレベルのものをまとめたものになります
ほぼ個人的な備忘録。。。

ちなみに以下のUdemyの講座を参考にしてます

https://www.udemy.com/course/ios-apps/

# 変数定義
- let : immutableな変数
- var : mutableな変数

# 型定義
```swift
// Int型でaという変数を定義
var a: Int = 123

// Double型でbという変数を定義
var b: Double = 123

// Intのオプショナル型でcという変数を定義(初期値はnil)
var c: Int?

// オプショナル型での四則演算(ダメな例)
var c: Int? = 5
var d: Int? = 7
let e = c + d // オプショナル型のままでは計算できない

// オプショナル型での四則演算(良いな例)
let f = c! + d! // !をつけることで明示的にnilでないことを定義することができる
```

# String型とInt型の足し合わせ
``` swift
let d = "私は"
let e = "歳です"
let f = 20

let g = d + "\(f)" + f
print(f) // 私は20歳です、と出力される
```

``` swift
"\()"
```
のなかに変数を入れることで、その変数をString型として扱うことができる

# 条件分岐
``` swift
let time = 15

if time < 12 {
    print("Good morning!")
} else if time < 18 {
    print("Good afternoon!")
} else {
    prnit("Good night!")
}
```

# 配列
``` swift
let a: [Int] = [1,2,3,4,5] //明示的に型を表したいときは左記のように書けばよいが、省略可
let b = a[0] // 1
let c = a[4] // 5

var e = [1,2,3,4,5]
//要素の追加
e.append(6) // [1,2,3,4,5,6]
//要素の置換
e[2] = 9 // [1,2,9,4,5,6]
//要素の削除
e.remove(at: 3) // [1,2,9,5,6] (3番目の要素を削除している)
```

# ディクショナリ型
***ディクショナリ型はデータのリストと違って、データの順序を持たない！！***

``` swift
let a = ["Taro":1985, "Hanako":1986]
let b = a["Taro"] // 1985
let c = a["Hanako"] //1986

var d:[String:Int] = ["Taro":1985, "Hanako":1986] // 型定義は省略可
// データの追加
d["Jiro"] = 1988 // ["Taro":1985, "Hanako":1986, "Jiro":1988]
// データの削除
d.removevalue(forKey: "Hanako") // ["Taro":1985, "Jiro":1988]
```

# ループ処理
``` swift
for i in 0..<10 {
    print(i) // 0 ~ 9までの数字が出力される
}

for i in 0...10 {
    print(i) // 0 ~ 10までの数字が出力される
}

var a:[Int] = [] // 空の配列を生成する際は型定義が必要
for i in 0..<10 {
    a.append(i)
}

for i in a {
    print(i) // aの中身がループで回される
}
```

# 関数
``` swift
// 引数なしの関数
func a() {
    print("Hello!")
}
a() // Hello!

let a = 4
let b = 6

// 引数ありバージョン
fnu add1(c: Int, d: Int) {
    let e = c + d
    print(e)
}
add1(c: a, d: b)

// 返り値のある関数
fun add2(c: Int, d: Int) -> Int {
    let e = c + d
    return e
}
let f = add2(c: a, d: b)
print(f) // 10
```

***add1(a,b)という書き方をするとエラーになる***
***返り値の型指定は"->"の先に記述すること***

# クラスとインスタンス
``` swift
// クラス定義
class Dog {
    var name = ""
    func bark() {
       let message = name + ": Bow-wow"
        print(message)
    }
}

// インスタンス生成
let pochi = Dog()
pochi.name = "Pochi"
pochi.bark() // Pochi: Bow-woo

let hachi = Dog()
hachi.name = "Hachi"
hachi.bark() // Hachi: Bow-wow
```

# インスタンスプロパティと型プロパティ
``` swift
class Dog {
    // インスタンスプロパティ(インスタンスで変更可能なもの)
    var name = ""
    // 型プロパティ(インスタンス化してないもので変更可能なもの)
    static var breed = ""
}

let pochi = Dog()
pochi.name = "Pochi"
pochi.name // Pochi

Dog.breed = "Akitaken"
Dog.breed // Akitaken
```

***staticをつけることで型プロパティの定義可能***
インスタンスプロパティの場合、クラスから変更不可
型プロパティの場合、インスタンスから変更不可

# インスタンスメソッドと型メソッド
``` swift
class Dog {
    // インスタンスメソッド
    func bark() {
        print("Bow-wow")
    }

    // 型メソッド
    static func barkStatic() {
        print("Bow-wow-wow")
    }
}

let pochi = Dog()
pochi.bark() // Bow-wow

Dog.barkStatic() // Bow-wow-wow
```

***先ほどと同様にstaticを先頭につけることで型メソッドになる***
インスタンスメソッドの場合、クラスから呼び出し不可
型メソッドの場合、インスタンスから呼び出し不可

# イニシャライザ
``` swift
class Dog {
    var name = ""
    var age = 0
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
}

let pochi = Dog(name: "Pochi", age: 5)
pochi.name // Pochi
pochi.age // 5
```

***インスタンスを作る際に引数として初期値を設定することが出来る***

# クラスの継承
``` swift
class Dog {
    var name = ""
    func bark() {
        let message = name + ": Bow-wow"
        print(message)
    }
}

// Dogクラスを継承したShibainuクラスの作成
class Shibainu: Dog {
    var age = 0
    func sayAge() {
        let message = name + ": I'm \(age) years old"
        print(message)
    }
}

let taro = Shibainu()
taro.name = "Taro" // Dogクラスを継承しているため、Dogのプロパティも利用可能
taro.age = 5 // 当然、Shibainuクラスのプロパティも利用可能
taro.bark() // Taro: Bow-wow　(メソッドもプロパティと同様)
taro.sayAge() // Taro: I'm 5 years old (メソッドもプロパティと同様)
```

# 構造体
``` swift
struct Dog {
    var name = ""
    var breed = ""
}

let pochi = Dog(name: "Pochi", breed: "Akitaken")
pochi.name // Pochi
pochi.breed // Akitaken

// オプショナル型を取ることも可能
struct Cat {
    var name: String?
    var breed: String?
}

let tama = Cat(name: "Tama", breed: nil)
tama.name // Tama
tama.breed // nil
```

# 列挙型
``` swift
enum Signal {
    case Blue
    case Yellow
    case Red
}

var sig: Signal // 変数sigがSignal型であると定義
sig = Signal.Blue // Signal型のBlueである
sig = .Blue // このように省略も可能

switch sig {
case .Blue:
    print("Go!")
case .Yellow:
    print("Caution!")
case .Red:
    print("Stop!")
}
```

# 参照渡しと値渡し
``` swift
// 参照渡し
class Dog {
    var age = 0
}

var pochi = Dog()
pochi.age = 5

var hachi = pochi
hachi.age = 7

pochi.age // 7
hachi.age //7

// -------------------------------------
// 値渡し
struct Cat {
    var age = 0
}

var tama = Cat()
tama.age = 5

var mike = tama
mike.age = 7

tama.age // 5
mike.age // 7

var a = 5
var b = a
b = 7
a // 5
b // 7
```

- ***クラスから作成したインスタンスは別の変数に代入しても同一のメモリを読み込むため、別の変数で値を変更したら、元のインスタンスの値も変わる(参照渡し)***
- ***一方で構造体やInt型などの変数は異なる変数に代入しても、それぞれの変数に異なるメモリを確保するため、別の変数で値を変更しても、元の変数の値は変わらない(値渡し)***

# クロージャ
``` swift
// クロージャの定義
let getAgeMessage = {(name: String, age: Int) -> String in
    let message = name + ": I'm \(age) years old"
    return message
}

let result = getAgeMessage("Pochi", 5)
print(result)

// クロージャを関数の引数として渡す
func sayAge(name: String, age: Int, getMessage: (String, Int) -> String) {
    let message = getMessage(name, age)
    print(message)
}

sayAge(name: "Hachi", age: 12, getMessage: getAgeMessage)
```

****クロージャを用いることで上で示したように関数の引数として呼び出せたりすることが可能になる**

# プロトコル
``` swift
// Fishというプロトコルの定義
protocol Fish {
    var color: String {get set}
    func swin()
}

 // Fishプロトコルを継承したSharkクラスの定義
class Shark: Fish {
    var color: String = "Blue"
    func swim() {
        print("Now quickly swimming...")
    }
}

// Fishプロトコルを継承したRayという構造体を定義
struct Ray: Fish {
    var color: String = "Brown"
    func swim() {
        print("Now slowly swimming...")
    }
}
```

***What is プロトコル***
- プロトコルを定義することで、そのプロトコルを継承したクラスや構造体はプロトコルで定義した通りのプロパティやメソッドを持たなければならなくなる
- 上の例でいうと、Fishというプロトコルにはcolorというプロパティとswimというメソッドがあるため、これを継承したShark、Rayはこれらを持たなければならなくなる

# デリゲート
``` swift
protocol SardineDelegate {
    func didEatSardine()
}

class Sardine {
    var delegate: SardineDelegate?
    fun eaten() {
        print("I was eaten...")
        delegate?.didEatSardine()
    }
}

class Shark: SardineDelegate {
    fun eat() {
        let sardine = Sardine()
        sardine.delegate = self
        sardine.eaten()
    }

    func didEatSardine() {
        print("I ate a sardine")
    }
}

let shark = Shark()
shark.eat()
```

***What is デリゲート***
すみません、まだよくわかってないです・・・
処理は流れとかはわかるけど、なんで必要？がまだ理解できてない・・
他の関数の処理を意識しないで済む、とか関数の責務の話なのかなと推測してるけど、よくわからん
分かり次第追記します。。。

# まとめ
昔、Cとかはよくいじってたので、書き方とか似てんじゃーんとかいって、なめてました。
デリゲートよくわかんないです。。
ただとりあえず、Swiftの書き方がなんとなくわかってきたので、つぎは簡単なiOSアプリ作れればなと思います(^^)
ではでは

# 参考文献
https://www.udemy.com/course/ios-apps/