- 投稿日:2021-07-20T22:32:29+09:00
UIProgressViewの簡単復習App
完成形はこんな感じです 機能説明 startボタンを押すと、UIProgressViewで作成したゲージがオレンジ色に変わっていきます。 ゲージとstartボタンの間のUILabelにゲージの進行状況を表示しています コードと簡単解説 .progressは初期値を入れています。0以上1以下の中から決めます .progressViewStyleは.barとdefalutから選択をします。.barを選択した場合、.backgroundColorを設定しないと.progressに値が入ってから、表示されるような見た目になります。 ProgressView import Foundation import UIKit class ProgressView:UIViewController{ let uiprogressView = UIProgressView() //インスタンス作成 func createProgressView(x: CGFloat, y: CGFloat, width: CGFloat, height: CGFloat, targetView:UIView){ uiprogressView.frame = CGRect(x: x, y: y, width: width, height: height) uiprogressView.progress = 0 uiprogressView.progressViewStyle = .bar uiprogressView.backgroundColor = .white //背景色 uiprogressView.progressTintColor = .systemOrange targetView.addSubview(uiprogressView) } } 今回は、20秒でProgressViewをいっぱいにします for文で1~20が入るprogressCountを用意します。DispatchQueue.main.asyncAfter(deadline: .now() + Double(progressCount)) {}内で、.setProgress()を毎秒使用し20秒間.progressの値に0.05を足されるようにします。 ViewController import UIKit class ViewController: UIViewController { @IBOutlet weak var progressLabel: UILabel! let progressView = ProgressView() var progressLabelCount = Int() override func viewDidLoad() { super.viewDidLoad() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) progressLabel.text = "0" progressView.createProgressView(x: 20, y: 200, width: self.view.frame.size.width - 40, height: 40, targetView: self.view) } @IBAction func start(_ sender: Any) { if progressView.uiprogressView.progress == 0{ for progressCount in 1...20{ DispatchQueue.main.asyncAfter(deadline: .now() + Double(progressCount)) { self.progressView.uiprogressView.setProgress(self.progressView.uiprogressView.progress + 0.05, animated: true) self.progressLabelCount = self.progressLabelCount + 5 self.progressLabel.text = String(self.progressLabelCount) } } }else{ //再度、startボタンを押した時とprogressView.uiprogressView.progressの値が0以外の時の処理 progressView.uiprogressView.progress = 0 self.progressLabel.text = "0" self.progressLabelCount = 0 for progressCount in 1...20{ DispatchQueue.main.asyncAfter(deadline: .now() + Double(progressCount)) { self.progressView.uiprogressView.setProgress(self.progressView.uiprogressView.progress + 0.05, animated: true) self.progressLabelCount = self.progressLabelCount + 5 self.progressLabel.text = String(self.progressLabelCount) } } } } } 終わり ご指摘や質問はコメントでお受けします。
- 投稿日:2021-07-20T14:54:56+09:00
Swift クロージャー(引数としてのクロージャ)
クロージャのキャプチャ クロージャはインスタンスが作られる時に外部にある変数を取り込んでインスタンスの一部にすることをキャプチャという キャプチャ func outer() -> () -> Void{ var x = 111 func inner(){ print("X is \(x)") x = x + 1//inner関数内で定義されていないx変数を操作している。ここがキャプチャ。 } return "キャプチャだよ" } クロージャによる強参照 swiftではARCという仕組みでメモリ領域内のオブジェクトを管理している。(他のオブジェクトから参照されている数を記録(参照カウント)を記録している) この参照カウントが1以上だった場合が強参照になる(0になった時メモリが開放される) つまりSWiftではデフォルトで強参照になるようになっている。 この設定により、2つのインスタンスが互いに強参照しあっている循環参照になることが多い。これは参照カウントが0になることがないため絶対にメモリの開放は起きない。これは後々にメモリリークによるパフォーマンスの低下に繋がる可能性がある。だからこそ、通常のデリゲートプロパティはweakを付けて弱参照にしている。 これはインスタンス化しているクロージャーにも発生しうる。これを回避するために[weak self]を付ける必要がある。 書き方(ドキュメントより) 参照.swift //強参照 クロージャーのインスタンスとクラスのインスタンスがイニシャライザすると参照しあう class A { var closure: (() -> Void)? let prop = "prop" // クロージャが、self.prop を強参照している func setClosure() { closure = { print("\(self.prop) が呼ばれました") } } deinit { print("解放されました") } } var a: A! = A() a.setClosure() a.closure!() a = nil //弱参照 class A { var closure: (() -> Void)? let prop = "prop" func setClosure() { // `[weak self]` と定義して、selfへの参照を弱参照にする closure = { [weak self] in if let weakSelf = self { print("\(self.prop) が呼ばれました") } } } deinit { print("解放されました") } } var a: A! = A() a.setClosure() a.closure!() トレイリングクロージャとは 通常クロージャは()の中に入れるが,()の外で{}処理を記述できる記法です。 引数の最後クロージャ型のみに書くことができる。returnがない closer.swift //通常であれば test(int:Int,int2:Int,callback:{x in print(x)}) //トレイリングクロージャを使用して実行 test(int:Int,int2){ print(x) } 通常の記法であれば関数の呼び出しの()が後まで多く広がってしまい、複数行にまたがると可読性が低くなってしまう 仮にクロージャのみが引数だった場合は引数のカッコも省略できる 引数としてのクロージャー 引数にクロージャは@escaping,@autoclosure属性の2つと上記のトレイリングクロージャが存在する 書き方 closure.swift func 関数名(引数名: @属性名 クロージャーの型名) { 関数呼び出し時に実行される文 } escaping属性 escapingとは関数に引数として渡されたクロージャがスコープを抜けても存在しうる場合に付与する属性。 関数に引数として渡されたクロージャは非同期的に実行される クロージャの実行時まで、外から持ってきた変数を保持しておく必要があるためキャプチャが必要になってくる。 具体例 外で定義されてある配列にクロージャー内からアクセスして、appendしていく時等、非同期処理の後にクロージャを発火させたい時 escaping.swift var array = [()->Void]() func addArray(operation: @escaping()->Void) { array.append(operation) } arrat.forEach{$0()} autoclosure属性 autoclosureとは引数をクロージャで包むことで遅延評価をすること そもそも遅延評価とは値が必要になるまでその値の評価を遅らせること 遅らせたい評価の引数にautoclosure属性をつけることで遅延評価が実装できる autoclosure.swift func auto() -> Bool { print("autoだよ") return true } func closure() -> Bool { print("closureだよ") return true } // closure() に @autoclosure を定義する func printFunc(auto: Bool, closure: @autoclosure () -> Bool) { if auto() { print("autoはtrueです") } else if closure() { print("closureはtrueです") } else { print("どちらともfalseです") } } // func2 に値を引数として渡す printFunc(func1: auto(), func2: closure())