#はじめに
みなさんdelegateとかのイメージはついてますか?
この記事では、私が勉強を始めて1,2ヶ月目で理解するのに苦労した部分(今回は7選)を中心に、
こんな解説があったらよかったなぁ〜と思っていたシリーズを集めて、
初心者がひっかかりやすいであろうところ、基本事項をQ&A方式でまとめました!
確認の意味でやりたい場合は、Questionだけみて答えを考えてください!
全くわからない人は、読みたいところを読んでみてください!☺️
#①letとvarの違い
まずは、一番初めの宣言の部分から!簡単な人には簡単です!
(ちなみに私は始めた頃さっぱりわかってませんでした、、😂)
Question
let と var の違いは?
Answer
letは定数、varは変数です。
variableのvarですね!
varは、1度データを入れても、後でデータを書き換えることができます。
一方、letは1度入れたデータを書き換えることができません。
ここで多くのみなさんはこう思うはず。
「全てvarで良いのでは、、?」
実際当時のわたしも、こう思っていました!笑
確かに、できないことはないのですが、もしletで良いところをvarで書いてしまうと、
変更するつもりのない変数を間違えて、変更してしまった時に気づかず、余計なエラーを自ら引き起こしてしまう、、という懸念があるので(複雑になるほどそうなるかもです)、しっかり使い分けていきましょう!
var number : Int = 0 //最初は0(初期値)
number = 2 //上書き保存されます
let number : Int = 0
number = 2 //これはアウト letで宣言したので初期値0から書き換え不可能です
#②オプショナル型
次に、非オプショナル型・オプショナル型・暗黙的オプショナル型についてです。
宣言のところで "!" をよく見かけませんか?
これってなんだろう、、とりあえずよくわからないけど、書いとこう!って人多いと思います!
そこで、以下の例題を踏まえ考えていきましょう!
Question それぞれのprint関数は何が出力されるでしょうか?
//非オプショナル型
var number0 : Int = 2
print(number0)
//オプショナル型
var number1 : Int?
number1 = 2
print(number1)
print(number1!)
//暗黙的オプショナル型
var number2 : Int!
number2 = 2
print(number2)
print(number1 + number2)
print(number1! + number2)
以下、答え合わせです。
Answer
//非オプショナル型
var number0 : Int = 2
print(number0) //2
↑これは非オプショナル型といって、nilを代入できないデータ型です。
そのため、宣言の時点ですでに初期値が入っているので、print関数にはそのまま初期値の2が出力されます。
Answer
//オプショナル型
var number1 : Int?
number1 = 2
print(number1)//Optional(2)
print(number1!) //2
オプショナル型はnilを代入できるデータ型です。
宣言した段階では、値は何も入っていないnilの状態です。
普通、nilだとクラッシュしますが、オプショナル型にすることで、(型の最後に!や?をつけることで)、number1という変数は包み紙(ラップ)で覆われている状態となるので、中身がnilでもクラッシュしません。
ここで、もし初期値を代入しないのに、!や?をつけないとnilが宙に浮いている状態となってクラッシュします。
次に、出力の部分です。
今回のnumber1は2を途中で代入しています。
しかしそのままprint(number1)と出力すると、先ほど説明した包み紙がついた状態なので、Optional(2)と出力されます。
この包み紙(ラップ)を外して数字の"2"として扱いたい場合は、オプショナル型の変数の後ろに!をつけてあげます。
このことをアンラップ(unwrap)と言います。
Answer
//暗黙的オプショナル型
var number2 : Int!
number2 = 2
print(number2) //2
暗黙的に宣言する(宣言の時に型の最後に"!"をつける)と、
その変数を次使う時に、包み紙(ラップ)が外れている状態になるので、先ほどのようにアンラップ(number2!とすること)する必要がありません。
以上のことを踏まえて、最後の足し算の部分をみてみます。
答えの1つ目は違う型同士の足し算になってしまうのでエラーとなります。
そのため、number1は2つ目のようにアンラップしてから使いましょう!
オプショナル型で宣言したときは、使用時にアンラップをお忘れなく!
Answer
print(number1 + number2) //Optional(2)+2
print(number1! + number2)//4
そもそもなんでOptional型いるの??について
例えばSNSでは、最初にユーザー登録をしますよね!
Facebookなどでは、名前は初めから必要ですが、プロフィール画像は初めから追加しなくてもアプリとして使えるはずです。
つまり、プロフィール画像はユーザーが写真を追加するまで、値が代入されない"nil"の状態を維持します。
このように全てのものに初期値があるわけではないのでOptional型が必要ってわけです!
#③引数
引数って言葉聞いたことありますか?
"いんすう"ではなく、"ひきすう"って読みます!
Question ()は何を表してますか?
//パターン1
func sample(){
//ここに何か処理をかく
}
Answer
()は、引数(ひきすう)です!
引数とは、関数やプログラムなどに渡す値のこと。処理が行われるためのトリガーのような存在です。
例えば、2進数⇄10進数に変換してくれる機械があったとします。
その機械に"1010"(2進数)と入力すると、"10"(10進数)と変換されます。
この場合、最初に入れた"1010"が引数、処理後に出てきた"10"が戻り値となります。
パターン1の場合、
()←これは、引数がnil(空)であるという意味です。
つまり、この関数が発動して、中に書いた処理が読み込まれるには、この関数がどこかで呼ばれる必要があります。
(トリガーとしての役割を担う引数が存在しないケースですからね!)
例えば、画面を開いた瞬間に、この関数の中身の処理が行われて欲しい場合は、viewDidLoadの中などに書いてあげましょう!以下のように書きます!
override func viewDidLoad() {
super.viewDidLoad()
sample()
}
こんな感じです。
もう一つみてみましょう!
//パターン2
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
パターン2に書いたtableViewのカッコ内
(_ tableView: UITableView, numberOfRowsInSection section: Int)
この部分には色々と書かれていますね!これも引数です!
これは元から引数が存在するので、先ほどのパターン1のように、この関数をどこかに書く必要はありません!
viewdidLoadに、tableview.dataSource = selfを書いてさえいればきちんと読み込まれます!
ちなみに、-> Intは、返り値(戻り値)と呼ばれるもので、この関数はInt型で返してね!と言われています。
よくある例で関数をミックスジュースに例えると、
引数:材料→関数:ミキサーにかけられている状態→返り値:出来上がったジュース
つまり、今回は出来上がったジュースをInt型で指定されているので、return 1のように整数で返す必要があります。
#④delegate
実際に、tableViewの画面遷移を扱うあたりから登場しますよね!
最初は、とりあえず書いとけ!みたいなノリで書いてるかもしれませんが、他のところでも色々お世話になると思うので理解しておきましょう!
tableViewを例にdelegateについて考えてみます。
Question
ViewController の上に TableView を配置した場合delegateはどうやってかくでしょうか?
//delegate周りで押さえておきたい3つのポイントを意識しよう!
Answer
//TableViewの場合
class ViewController: UIViewController,UITableViewDelegate { //①ここにUITableViewDelegate(protocol)をかく
@IBOutlet var TableView : UITableView!
override func viewDidLoad() {
super.viewDidLoad()
TableView.delegate = self //②上で追加したプロトコルの実装をお任せ
}
//③delegateを元にした実装
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// セルがタップされたら行われる処理
}
詳しく説明していきます。
まず、delegateを実装するには、3つの要素が必要になります。
1.protocol
2.処理を依頼するクラス(この場合はTableView)
3.依頼された処理を実行するクラス(この場合はViewController)
ViewControllerの上にtableViewを配置している構造を、わかりやすく、例えて
1階がViewController、2階がtableViewのマンションがあるとします。
この1,2階は繋がっていません。(という設定)
delegateが書かれていないと、2階にあるものを1階に届けたいけどどうしよう繋がってないし、、っていう状況です。
この状況打破のため、2階のtableViewが実はわたしハシゴ持ってるよ!っていう手段を提示します。
これがprotocolです。(上でいう①)
次に、tableView自身が
「ハシゴは持ってるけど、設置はできないから、1階のViewControllerがやってね!実装は任せたよ!」
っていうのがprotocolの実装を任せている上の②の部分です。
③はハシゴが設置された結果できるようになったこと。つまり今回は、tableViewがタップされると、その下のViewcontrollerが"タップされたこと"を認識できて、タップされたらどうしたいかの処理を(コーディングしたものを)ViewControllerがやってくれることになります。
それではtextfieldで練習です!
Question
//ViewControllerの上にtextfieldを配置した場合
textfield.delegate = self
これはなんのために書いてるのでしょうか?
Answer
これも先ほどの説明同様に、textfieldのprotocolをViewControllerに任せているって意味です!
皆さんはtextfield(例えばSNSのログインでユーザーIDとかパスワードとか)で文字を打ち込んだ後、enterを押してキーボードを閉じていませんか?これができているのはこのdelegateのおかげなのです!
textfieldだけではキーボードを閉じることができないので、delegateを使ってViewControllerにその処理をお任せして閉じてもらっています!
1.protocol
→UITextFieldDelegate
2.処理を依頼するクラス(この場合はTextField)
→enter押されたら、押されたタイミングをViewControllerに知らせてキーボード閉じる処理を依頼
3.依頼された処理を実行するクラス(この場合はViewController)
→ViewControllerが2の依頼を実行(キーボードを閉じる)
delegate周りの3点は覚えておきましょう!
#⑤append
英語のappendって意味知ってますか?
appendはaddの派生語ですね!つまり"追加"って感じです。
以下で、配列にappendするコードをみていきます。
Question
var memoArray = ["りんご","ゴール","ルール"]
@IBAction func sample(){
memoArray.append("日本")
print(memoArray)//ここで出力されるものは?
}
Answer
["りんご","ゴール","ルール","日本"]
となります。
このように普通にappend(追加)した場合は1番最後に追加されます!
では、複数追加したい場合や、元の配列の途中に追加したい場合はどうなるでしょうか、、?
Question
var memoArray = ["りんご","ゴール","ルール"]
@IBAction func sample(){
//①"ルビー"と"ビー玉"を配列の最後に追加するコードを書いてください→["りんご","ゴール","ルール","ルビー","ビー玉"]となればおけ
//②"うり"をmemoArrayの最初に追加してください→["うり","りんご","ゴール","ルール"]となればおけ
}
Answer
①memoArray.append(contentsOf: ["ルビー","ビー玉"])
②memoArray.insert("うり", at: 0)
それぞれ上記のようにかけば対応できます!
②で、配列の一番初めは0番目になるので、1にしないようにそこだけ注意しましょう!
追加されるもの.append(追加したいもの)
となります!
#⑥protocol
先ほど④のところで少しだけ登場したprotocolです!
④では、UITableViewDelegateなど1ワードで登場しましたが、今回は少し長いprotocolの登場です。
Question
Twitterのいいね機能(セルの上のボタンをタップ)
はどのような仕組みになっているでしょうか?
ViewController に TimelineTableViewCell のカスタムセルを配置した場合を考えます!
protocol TimelineTableViewCellDelegate{
func didTapButton(timelineTableviewCell: UITableViewCell, button: UIButton)
}
class TimelineTableViewCell: UITableViewCell {
var delegate: TimelineTableViewCellDelegate?
@IBAction func Button(button: UIButton){
self.delegate?.didTapButton(timelineTableviewCell: self ,button: button)
}
}
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, TimelineTableViewCellDelegate {
func didTapButton(timelineTableviewCell: UITableViewCell, button: UIButton) {
//ここにボタンをタップした後の処理
}
}
Answer
protocolは④のdelegateで書いた通り、delegate処理に必要な要素の1つです。
今回は④とは違い、デフォルトに存在しないものを使いたいので、protocol宣言をします。
//protocol宣言で、これが使えますっていう手の内を公開
protocol TimelineTableViewCellDelegate{
func didTapButton(timelineTableviewCell: UITableViewCell, button: UIButton)
}
delegate周りの時に登場する3つの役割は、今回の場合こんな感じです!
1.protocol
→TimelineTableViewCellDelegate(宣言して自分で置いたもの)
2.処理を依頼するクラス(この場合はTimelineTableViewCell)
→ボタン押されたら、押されたタイミングをViewControllerに知らせる
3.依頼された処理を実行するクラス(この場合はViewController)
→2の依頼を受けて、ボタンが押された後の処理を実行
#⑦for文とwhile文
for文とwhile文は繰り返しのループ文ですよね!
それぞれ使い分けしていますか?
一度わかれば簡単です見ていきましょう!
Question それぞれprint関数には何が出力されるでしょうか?
for i in 0...9{
number = Int(arc4random_uniform(20))
print(number)
}
while number < 10{
number = Int(arc4random_uniform(20))
print(number)
}
Answer
1つ目は、乱数発生を10回繰り返すので、0~19までの20個の数字で発生した乱数が10個出力されます。
2つ目は、0~19までの中で乱数が発生して、その発生した数字が10未満だったら、while文が繰り返されますが、10以上の乱数が表示された場合はそこで繰り返し文の読み込みは終了します。なので、出力される個数は一定ではありません。
回数が決まってる時はfor文を使います。
今回は10回、回したいっていう繰り返し文なので
for i in 0...9
としました!
一方、ある条件に達するまで繰り返したい場合はwhile文を使います。
今回の条件は number < 10 ということ。
numberの値が0~9の場合は永遠にwhile文が繰り返されるという条件が前提です。
ちなみにfor文は配列と組み合わせるのに最適です!
let memoArray = ["りんご","ゴール","ルール"]
for i in memoArray{
}
このように書くと、宣言した配列memoArrayのそれぞれの単語にアクセスすることが可能になります!
また、配列の何番がなんの言葉か、というindexも取得できます
let memoArray = ["りんご","ゴール","ルール"]
for (index, memo) in memoArray.enumerated() {
print(index, memo)
// 0 りんご
// 1 ゴール
// 2 ルール
}
以上のように、print関数に出力されるので、indexを取得すれば、配列の何番目以上はこうしたい、みたいな条件分岐などをすることができます!
#⑧guard let と if let の違い
こちらを参照してみてください!
https://qiita.com/solty_919/items/8b22c8b30cd1a5596c83
#⑨overrideとは
こちらを参照してみてください!
https://programfromscratch.com/swift%E5%85%A5%E9%96%80override%E3%81%AE%E6%84%8F%E5%91%B3%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9/