【プログラミング初心者】Swift基礎~メソッド・関数~

# はじめに
今回はSwiftでのメソッド作成方法についていくつか紹介します。

# メソッド・関数とは
## 関数
そもそも**関数**がどういうものか説明します。

簡単にいうと処理の塊です。

プログラムにはmain関数と呼ばれるプログラムを実行した時最初に呼ばれる処理があります。
(iOSアプリをSwiftで開発する場合は内部で定義されているので見れませんが)
極論をいうとこのmain関数さえあれば関数を使わなくてもプログラムは書けます。

ですが現実的に数万行に及ぶ処理がずらずらと書かれていても処理を把握することは困難です。
そのため関数に処理を分けてあげて関係する処理を分割してあげています。

さらに同じ処理をする場合は関数に書くことで重複するコードを書かなくて済みます。

関数は数学で使っていた関数と似ており、何かInputを与えて処理の結果をOutputとして返します。
`y = ax + b`という１次関数があります。
これはxに何かInputを与えた結果yというOutputを得るという処理です。
これをプログラムで書くと以下になります。

```swift
let a = 5
let b = 10
func linearFunction(x: Int) -> Int {
    return a * x + b
}

let y = linearFunction(x: 3)
```
この何かしら処理をする`linearFunction`のようなものを関数と呼びます。

### 引数
関数には必須ではありませんが**引数**を設定できます。
上記の例で言うと`x: Int`が引数です。

引数は関数へのInputです。
この与えられた引数を使って処理を制御します。
もちろん引数なしで制御可能な場合は定義しなくても問題ありません。
必要とする場合は型アノテーションが必須となります。

与えられた引数は`let`つまり定数として定義されます。
従って変更することはできません。
あくまで与えられた値を使って何か処理をするという用途になります。

また複数指定することができます。
複数指定する場合は以下のようになります。

```swift
func function(arg1: Int, arg2: Int, arg3: String) {
}
```

### 戻り値・返り値
戻り値は関数からのOutputです。
関数が値を返してくる値を戻り値や返り値と呼びます。
戻り値なしの場合は不要ですが、戻り値がある場合は`-> 戻り値の型`というように戻り値の型を明示する必要があります。

```swift
func function(arg1: Int, arg2: Int, arg3: String) -> Int {
}
```
戻り値を設定した場合は必ず何かしらの値を返さなければなりません。

戻り値は`return 値`という構文で返します。
`return`が呼ばれると後続の処理が呼ばれないので注意してください。

```swift
func function(arg1: Int) -> Int {
    return arg1 + 1
    print(arg1) // 実行されない
}
```
戻り値なし場合以下のように値なしreturnできます。

```swift
func function() {
    return
}
```
補足ですが戻り値の場合暗黙的に`Void`という戻り値が返っています。
これは何もないというような意味です。
なので上記の例は以下と同じ意味です。

```swift
func function() -> Void {
    return
}
```
## メソッド
**メソッド**というものもあります。
メソッドも関数の一種で、[クラス](https://qiita.com/euJcIKfcqwnzDui/items/f6e41f6b8f068c620ac6#%E3%82%AF%E3%83%A9%E3%82%B9)が持つ関数のことです。

基本的にSwiftはクラス内で関数を定義しているため、メソッドという言葉を使うことが多いです。
ですが関数といっても間違いではないので問題ありません。

定義の仕方は関数と同じです。

## 呼び出し方
関数の場合、以下のようにそのまま直接呼び出すことができます。

```swift
var returnValue = function()
```
`print()`なども関数なのでそのまま呼び出すことができます。

メソッドの場合、`オブジェクト.関数名()`という形で呼び出します。

```swift
let object = Object()
let returnValue = object.function()
```
クラス内で自分のメソッドを呼び出す場合は以下のようにします。

```swift
let returnValue = self.function()
```
`self`は自分自身のオブジェクトを示します。他の言語だと`this`とかになったりします。
実はSwiftの場合`self`を省略しても言語上問題ありません。

```swift:SampleClass.swift
class SampleClass {
    func function() -> Int {
        return 1 + 1
    }

    func test() {
        let selfvalue = self.function()
        let noSelfValue = function()
    }
}
```
これはチームのコーディング規約に則って付けるか付けないか決めてください。

# Swiftメソッド記法
Swiftは言語として少し特殊で引数の書き方がいくつかあります。
よく使う例を紹介していきます。

### デフォルト値指定
引数にデフォルト値を指定することができます。
デフォルトを設定した引数は引数なしで呼び出すことができます。

```swift
func function(arg1: Int = 0, arg2: Int = 0) {
    print("arg1: \(arg1), arg2: \(arg2)")
}

self.function()                    // arg1: 0, arg2: 0
self.function(arg1: 10)            // arg1: 10, arg2: 0
self.function(arg2: 10)            // arg1: 0, arg2: 10
self.function(arg1: 10, arg2: 10)  // arg1: 10, arg2: 10
```

### 引数のラベルを省略
以下のように引数前に`_`をつけて定義すると、メソッドコールのとき引数の`arg1: `というラベルを省略することができます。

```swift
func function(_ arg1: Int, arg2: Int) {
}

self.function(1, arg2: 1) // OK
self.function(1, 1) // NG
self.function(arg1: 1, arg2: 1) // NG
```

### 引数のラベルに別名を付ける
ラベルに別名をつけることができます。

```swift
func convert(from value: Int) -> String {
    return "\(value)"
}

let stringValue = self.convert(from: 1) // OK
let stringValue = self.convert(value: 1) // NG
```
補足ですが、この方法はSwfit特有のものではありますがよく使います。
よく`from` `to` `with`のような前置詞を使って別名を付けメソッド自体が英文として読めるように書くことが多いかと思います。

# メソッドの引数について
[以前](https://qiita.com/euJcIKfcqwnzDui/items/58c8bc5ced324a64abb7)変数がどのようにメモリに確保されるのかを説明しました。
メソッドの引数の場合はどうか見ていきます。

## 値渡し
[先述](#引数)しましたが引数は`let`として新しく定義されているのと同義です。
そのため引数も変数もメモリ上の扱いは同じになります。

以下のように構造体とメソッドを定義し呼び出してみます。

```swift
struct Dog {
    var name: String
}

func update(with newName: String, dog: Dog) {
    dog.name = newName
}

var myDog = Dog(name: "ポチ")

print("更新前: " + myDog.name)
self.update(with: "ミケ", dog: myDog)
print("更新後: " + myDog.name)
```
この場合メソッド定義の部分で`Cannot assign to property: 'dog' is a 'let' constant`とSwiftのエラーが発生し実行はできません。
これは引数が`let`で定義されているため発生したエラーです。
ですが、もし仮にSwiftがエラーを返さないと仮定します。
その場合であってもメソッド内の`dog.name`は「ミケ」に更新されますが、元となっている`myDog.name`は更新されません。
これは構造体が値型のため引数として渡された`dog`は`myDog`のコピーとなっているためです。
従って仮に実行できたとすると以下のような出力になります。

```:出力
更新前: ポチ
更新後: ポチ
```

このように値そのものを引数に渡すことを**値渡し**といいます。

## 参照渡し
ではクラスの場合はどうでしょう？
以下のようにクラスとメソッドを定義し呼び出してみます。

```swift
class Cat {
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

func update(with newName: String, cat: Cat) {
    cat.name = newName
}

var myCat = Cat(name: "タマ")

print("更新前: " + myCat.name)
self.update(with: "トラ", cat: myCat)
print("更新後: " + myCat.name)
```
これはエラーは発生しません。
クラスの場合、参照型のため変数が`let`で定義されていても変数の値そのものを書換えているわけではないのでこれを実行できます。
実行すると以下のように出力されます。

```:出力
更新前: タマ
更新後: トラ
```
`myCat.name`の値が更新されていますね。
参照型は引数には`myCat`へのアドレスをコピーとして渡しているため同じオブジェクトを参照しており、そのため内容の更新ができたというわけです。

このように引数にアドレス、つまり参照を渡しているものを**参照渡し**と言います。

## 値型を参照渡ししたいときは？
基本的にはやりません。
その場合は以下のように戻り値として新しいオブジェクトを返すように実装する方法が一般的です。

```swift
func update(with newName: String, dog: Dog) -> Dog {
    var newDog = dog
    newDog.name = newName
    return newDog
} 

let myDog = Dog(name: "ポチ")
let newDog = self.update(with: "ミケ", dog: myDog)
print(newDog.name) // ミケ
```

それでもどうしても構造体を参照渡ししたいということもあるかと思います。
その場合は以下の方法で実装できます。

```swift
func update(with newName: String, dog: inout Dog) {
    dog.name = newName
} 

var myDog = Dog(name: "ポチ")

print(myDog.name) // ポチ
self.update(with: "ミケ", dog: &myDog)
print(myDog.name) // ミケ
```
`update`実行前と後で`myDog.name`の値が変わっていることから参照渡しになったことがわかります。

引数が`dog: inout Dog`となりました。
`inout`を引数の型の前に付けると参照型という意味になります。

引数に渡す値は`&myDog`となっています。
変数名の前に`&`を付けるとその変数のアドレスを意味します。
myDogはスタック領域に確保されているのでそのスタック上のアドレスが引数として渡されました。
その結果参照渡しとなり`name`を更新できるようになりました。

# 最後に
今回はメソッドについて、またそのメソッドの定義の仕方や引数の性質について説明しました。

引数の定義の仕方はおそらくチームによって別れてくるところかもしれません。
どれでも書けるようにしておくのが無難と言えます。

今回の内容は以上です。
本記事とは別でプログラミング未経験からiOSアプリ開発が行えるようになることを目的とした記事を連載しています。
連載は以下にまとめていますのでそちらも是非もご覧ください。
http://naoyalog.com/