危機感を持った理系学生のプログラミング日記
こんばんわ🦊
プログラミングは慣れなので、毎日少しでもいいから触るのをモットーに日々過ごしています。
そんなこんなで今日はクロージャについて少し書こうと思います。
クロージャとは
クロージャとは、一言で言うと名前がない関数のことです。
変数や引数に関数の中身を直接代入できるため、グローバル変数の宣言をなるべく減らしたい場合や、関数の実行結果を次の処理で続けて使用する関数を作成したい場合に使用します。
クロージャの書き方
クロージャは以下の基本フォーマットのように関数名を付けず引数、処理、戻り値を定義します。
{(引数名:引数の型) -> (戻り値の型) in
処理
return 戻り値
}
例:
{(arg:Int) -> Int in
arg += arg
return arg
}
以下のコードは、Int型の引数を2つとクロージャを引数に関数を呼び出し、関数の中でクロージャを実行するものです。
func calcPrice(a:Int, b:Int , total:(Int,Int) -> Int){
print(total(a, b))
}
calcPrice(a:100, b:10, total:{(a:Int, b:Int) -> Int in return a * b})
関数の中でクロージャを実行して
クロージャで関数を呼びだし?
ややこしいですね。。。
でも今後も出てくると思うので慣れようと思います。
参考サイト
危機感を持った理系学生のプログラミング日記
コンバンワ🦊
今日は早めに書いています。(現在時刻20:43)
さて、今日は地図アプリを作りながらデリゲートを深堀りしました。
ややこしいですがなんとか概念がわかってきた気がします🦊
デリゲートの流れ
まず当たり前ですが、デリゲートを使うには2つ以上のクラスが必要です。
デリゲートを委託するクラスをBクラス、委託されるクラスをAクラスとします。
Bクラスでの処理
まずプロトコルを書きます。
protocol SearchLocationDelegate {
func searchLocation(idoValue:String,keidoValue:String)
}
var delegate:SearchLocationDelegate?
なんらかのイベントが発生した時(今回はOKボタンが押された時)にメソッドを起動するように記述。このBクラスでメソッドが起動されたタイミングを、「タイミングB」とします。
@IBAction func okAction(_ sender: Any) {
//入力された値を取得
let idoValue = idoTextField.text!
let keidoValue = keidoTextField.text!
//両方のテキストフィールドが空じゃなければ閉じる
if idoTextField.text != nil && keidoTextField.text != nil{
//こっちで引数を渡しながらデリゲートメソッドを呼ぶ
delegate?.searchLocation(idoValue: idoValue, keidoValue: keidoValue)
dismiss(animated: true, completion: nil)
}
}
Aクラスでの処理
Bクラスで作成したプロトコルを使えるように、Delegateプロトコルを継承する。
class ViewController: SearchLocationDelegate {
}
遷移先のSegueIDが"next"(Bクラスに遷移する時に)ならAクラスの中でBクラスのインスタンスを作り、Bクラスのプロパティ(delegate)にself(自分自身なのでA)を代入する。
このBクラスのプロパティに自分自身を代入して、Bクラスのデリゲートを使えるようにしたタイミングを「タイミングA」とします。
if segue.identifier == "next"{
let nextVC = segue.destination as! NextViewController
nextVC.delegate = self
}
デリゲートメソッドの具体的な処理を記述する
//任されたデリゲートメソッド
func searchLocation(idoValue: String, keidoValue: String) {
if idoValue.isEmpty != true && keidoValue.isEmpty != true{
let idoString = idoValue
let keidoString = keidoValue
//緯度、経度からコーディネート
let coordinate = CLLocationCoordinate2DMake(Double(idoString)!,Double(keidoString)!)
//表示する範囲を指定
let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
//領域を指定
let region = MKCoordinateRegion(center: coordinate, span: span)
//領域をmapViewに指定
mapView.setRegion(region, animated: true)
//緯度経度から住所へ変換
convert(lat: Double(idoString)!, log: Double(keidoString)!)
//ラベルに表示
addressLabel.text = addressString
}else{
addressLabel.text = "表示できません"
}
}
重要な事
タイミングBとタイミングAは同じタイミングで完全にイコールなので、
OKボタンが押された→タイミングB発動!!!! それと同時にタイミングAも発動!!!
→ Aクラスに画面が遷移→Aクラスでのデリゲートメソッドが実行されてる
ていう流れになります。
参考になったサイト貼っときます。
今日はここまで
拙い文章で恥ずかしい限りですが、今後も書いていこうと思います🦊
ではまた。
危機感を持った理系学生のプログラミング日記
コンバンワ🦊
只今、午前3時半です。授業もあるので早めに寝ないといけませんが今日やったことを備忘録として残しときます。
今日は、UITableViewとProtocolを少し触れました。
UITableView
UITableViewは、テキストやイメージを行単位で表示することが出来ます。
メモ帳とかもUITableViewを用いています。
色々書く決まりがあり、慣れたらそんなにも難しくないのかなと言う印象🦊
簡単で分かりやすいコードを貼っていきます。
import UIKit
class ViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!
let prefectures = ["東京都", "神奈川県", "千葉県", "埼玉県", "茨城県", "栃木県", "群馬県"]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.delegate = self
tableView.dataSource = self
}
// TableViewに表示するセルの数を返却します。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.prefectures.count;
}
// 各セルを生成して返却します。
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .default, reuseIdentifier: "myCell")
cell.textLabel?.text = self.prefectures[indexPath.row]
return cell
}
}
これの結果が
こうなります。もっと詳細な設定をするときは命令が増えますが、まあ最初はこんな感じで。
Protocol
情報系の勉強をしているとちょくちょく出てくるProtocolと言う単語。
その分野によって意味は違いますが、「決まり事」と言う意味で使われる事が多いです。
protocolの宣言
protocol catchProtocol {
//規則を決める
func catchDate(count:Int)
}
他クラスのprotocolを使う
//protocolを宣言
class ViewController: UIViewController,catchProtocol
func catchDate(count: Int) {
//自由に
}
具体的な処理は委託先のクラスが決められるというなんともややこしい仕様。
でも自クラスから他のクラスへ引数を渡したりもできるので便利ではあると思うが慣れないですね。
まだ上手く言語化ができていないのでもっとここは詰めます。
今日はここまでで。お疲れ様でした🦊
危機感を持った理系学生のプログラミング日記
こんにちは🦊
夏休みが明け、大学が始まりました。
そんな中でもSwiftはちょこちょこ弄ってたのでそこで気になった点を書いていきます。
画面遷移の方法
1.ナビゲーションを使った画面遷移
Navigation Controllerを出す。
//ナビゲーションを出す画面遷移
let nextVC = storyboard?.instantiateViewController(withIdentifier: "next") as! NextViewController
//nextVC.count2 = count
navigationController?.pushViewController(nextVC, animated: true)
このidentifierは遷移先のStoryboardIDに設定する。
2.何かのタイミングで画面を遷移&値を渡しながら画面遷移
//Story board SegueのID "next"のとこに画面遷移をする
performSegue(withIdentifier: "next", sender: nil)
//segue準備
//画面遷移をする時にここが自動的に呼ばれる
//値を渡したりしたい時
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if(segue.identifier == "next"){
let nextVC:NextViewController = segue.destination as! NextViewController
nextVC.count2 = count
}
}
3.ボタン等を押した時に画面遷移
初期画面から遷移先の画面への遷移はbuttonをドラッグして設定できるが、逆はできない。
なので遷移先の画面から、初期画面に戻すにはメソッド(dismissメソッド)を用いる
//ボタンを押したらViewControlleを閉じるようにする
@IBAction func back(_ sender: Any) {
//ViewControllerを閉じるメソッド
dismiss(animated: true, completion: nil)
}
画面遷移だけでも色んな方法があります。
習ったやつをまとめてみました。メモ代わり🦊
オプショナル
Swiftの便利機能の1つであるオプショナルですが、慣れるまでは厄介極まりありません。
オプショナル型の特徴
- オプショナル型で宣言した変数はnilを代入できるが、反対に非オプショナル型の変数にはnilを代入することができない
- 変数をオプショナル型にするにはString、Intのようなデータ型の最後に"?"か"!"をつける
- 変数宣言で用いる"?"・"!"とそれ以外で使う"?"・"!"は別物であり、変数宣言で使用する方がオプショナル型
非オプショナル型の変数は普通に扱う変数です。一方nilを扱うことのできるオプショナル型の変数は通常とは扱い方が少し異なります。
オプショナル型の変数を通常の変数と同様に扱おうとするとおもわぬエラーが起きます。そのため、オプショナル型の値を通常の値に変換するアンラップという方法が必要になります。
そもそもOptional(値)とはどのような状態でしょうか。
Optionalは値を包み込むラップ(包み紙)のイメージです。オプショナル型は値をOptionalというラップ1枚で包み込んでいます。すると、たとえ中身がない(=nil)状態でも包み紙だけは存在するため、とりあえず扱うことができます。
オプショナル型の値がnilでも使えるのは、この包み紙が存在しているためです。
しかし、この便利な包み紙があるために値はラッピングされ、直接扱うことができません。扱うためにはラップを取り除き、中身の値を取り出さなくてはいけません。
この包み紙を取り除き、値を取り出すことをアンラップと言います。
アンラップの方法はいくつかあります。代表的なアンラップの方法は以下です。
- Forced Unwrapping (強制的アンラップ)
- Optional Binding (オプショナルバインディング)
- Optional Chaining (オプショナルチェイニング)
こういうのは暗記する必要はないと思っているので、やりながら慣れます🦊
参考サイト
プロトコルとデリゲート
プロトコルは系統の似たクラスや構造体を作りたい時に最低限の実装ルールを決めている仕様書。
デリゲートはデザインパターンの1つで、処理の流れをプロトコルで定義したメソッドを使って書いていきます。
プロトコルを使用して、2つの数値の計算を行うサンプルを紹介します。
サンプルプログラム:
実行結果
8
プロトコルCalculationは、2つの数値をプロパティに持ち、計算を行うメソッドを定義したプロトコルです。
構造体AddはプロトコルCalculationを適合します。
そのため、プロトコルCalculationで定義されているcalcメソッドを実装しないと、コンパイルエラーが発生します。
calcメソッドでは、num1とnum2を足した値を返すように実装しています。
最後に「Add(num1: 5, num2: 3)」でnum1とnum2に値が設定し、calcメソッドを呼び出します。2つの数値が足した値が返されているのがわかります。
構造体Addのcalcメソッドの処理は後で変更することができますが、プロトコルCalculationを適合し、calcメソッドが実装されていることが保証されているので、呼び出す側は呼び出し方を変える必要はありません。
これも慣れるまでは難しいので使い倒さねば。
参考サイト
今日もお疲れ様でした
着々と進んできてます。進みは遅いですが。。。
また進捗があれば投稿します。お休みなさい🦊
危機感を持った理系学生のプログラミング日記
プログラミング日記
こんばんは、絶賛夜中の3時です🦊
時間が経つのが早いですね。
swiftの学習を今日一日したのでそれを書いていきます。
Xcodeのアップデートは長いので時間に余裕のある時にやるのがおすすめです。
Swiftを触ってみて
Swiftを少し触った感じ、UnityとJavaを足し合わせたかのような感じ?
オブジェクト指向言語なので、Javaに似るのはしょうがないとしても、プログラミングを書くだけでなく、ボタンを設置したりドラックしたりと結構アクティブな事をします。
慣れるまでは大変そうです。
理解ができていない所
//timerにTimerオブジェクトを保持
var timer = Timer()
func startTimer(){
//タイマーを回す 0.2秒毎にあるメソッドを呼ぶ
timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(timerUpdate), userInfo: nil, repeats: true)
}
@IBAction func stopBtn(_ sender: Any) {
//imageViewの画像の流れを止める
//startBrnを押せるようにする
startButton.isEnabled = true
stopButton.isEnabled = false
timer.invalidate()
}
上記のコードで、timerにTimerメソッドを代入しているのがよく分かりません。
代入する事で便利に使おうとしているのはなんとなく分かるけど、なんかこうモヤモヤする。
timerにTimer.scheduledTimerを代入して使う事で、timerにTimer.scheduledTimer が宿るので、timer.invalidate()でタイマーを止めてると。
Timerメソッドはtimerに代入する前提なのかな。。??
まあなんとなくは理解してます🦊
あとは、プロパティーとメソッドの違いも混乱しました。
ざっくり言うと、プロパティーが静的な情報で、メソッドが動的な情報。
Javaで言う、属性がプロパティでメソッドはメソッドって感じかな?
色々書きたい事がありますが眠いのでここまでで
ではまた🦊