質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

707閲覧

メソッドが呼び出される順序が理解できず困っています。

tatuya51

総合スコア23

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

1クリップ

投稿2020/04/11 00:48

編集2020/04/11 01:13

前提・実現したいこと

初めて質問するため伝わりにくいところがあるかもしれませんがご容赦下さい...
現在「たった2日でマスターできる iPhoneアプリ開発講座」のタイマーアプリ作成しております。

太字で表記されているdisplayUpdateメソッドがどういった順序、タイミングで呼び出されるかがいまいち理解できません。
私の中ではdisplayUpdateメソッドがなぜ毎秒呼び出され、残り時間をラベルに表示できるのか他の動作と関連性を
見出せない状態です...

また、scheduledTimerメソッドが1秒毎に実行される度に、timerInterruptメソッドが呼び出されるといった解釈で正しいのでしょうか?

該当のソースコード

swift

1import UIKit 2 3class ViewController: UIViewController { 4 5 var timer: Timer! 6 7 var count = 0 8 9 let settingKey = "timer_value" 10 11 override func viewDidLoad() { 12 super.viewDidLoad() 13 // Do any additional setup after loading the view. 14 15 let settings = UserDefaults.standard 16 17 settings.register(defaults: [settingKey: 10]) 18 19 } 20 21 22 @IBOutlet weak var countDownLabel: UILabel! 23 24 @IBAction func settingButtonAction(_ sender: Any) { 25 26 if let nowTimer = timer { 27 28 if nowTimer.isValid == true { 29 30 nowTimer.invalidate() 31 } 32 } 33 34 performSegue(withIdentifier: "goSetting", sender: nil) 35 } 36 37 38 39 @IBAction func startButtonAction(_ sender: Any) { 40 41 if let nowTimer = timer { 42 43 if nowTimer.isValid == true { 44 45 return 46 47 } 48 } 49 50 timer = Timer.**scheduledTimer**(timeInterval: 1.0, target: self, selector: #selector(self.timerInterrupt(_:)), userInfo: nil, repeats: true) 51 52 } 53 54 55 @IBAction func stopButtonAction(_ sender: Any) { 56 57 if let nowTimer = timer { 58 59 if nowTimer.isValid == true { 60 61 nowTimer.invalidate() 62 } 63 } 64 } 65 66 67 68 func **displayUpdate()** -> Int { 69 70 let settings = UserDefaults.standard 71 72 let timerValue = settings.integer(forKey: settingKey) 73 74 let remainCount = timerValue - count 75 76 countDownLabel.text = "残り(remainCount)秒" 77 78 return remainCount 79 80 } 81 82 83 @objc func **timerInterrupt**(_ timer: Timer) { 84 85 count += 1 86 87 if displayUpdate() <= 0 { 88 89 count = 0 90 91 timer.invalidate() 92 93 let alertController = UIAlertController(title: "終了", message: "タイマー終了時間です", preferredStyle: .alert) 94 95 let defaultAction = UIAlertAction(title: "OK", style: .default, handler: nil) 96 97 alertController.addAction(defaultAction) 98 99 present(alertController, animated: true, completion: nil) 100 101 } 102 } 103 override func viewDidAppear(_ animated: Bool) { 104 105 count = 0 106 107 _ = displayUpdate() 108 } 109 110 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TsukubaDepot

2020/04/11 01:04

このままではソースコードが見にくいので、引用したいソースコードの前後を ```swift (ソースコード) ``` と囲ってもらえますでしょうか。 他の質問者さんと同じく、読みやすいソースコードの形で表示できますし、コメントも付けやすくなります。 https://teratail.com/help#about-markdown
TsukubaDepot

2020/04/11 01:11

たとえば、処理の流れをわかりやすくする方法として、関数が呼ばれた後に print(#function) を実行することで、どのような順番で関数が呼ばれるのかをデバッグスクリーンで確認することもできます。 たとえば、 override func viewDidAppear(_ animated: Bool) { print(#function) count = 0 _ = displayUpdate() } のような感じです。 まずはこのような感じでいろんな関数(メソッド)にprint()を加えて、処理順番を表示させてみるのもいいと思います。
guest

回答1

0

ベストアンサー

毎秒呼び出しがかかる、というのは

また、scheduledTimerメソッドが1秒毎に実行される度に、timerInterruptメソッドが呼び出されるといった解釈で正しいのでしょうか?

という認識であっています。

では、なぜ呼び出しごとに書き換わるのかというと、

swift

1 @objc func timerInterrupt(_ timer: Timer) { 2 3 count += 1 4 5 // **この部分** 6 if displayUpdate() <= 0 { 7 // 以下略 8 } 9 }

この部分でdisplayUpdate()を呼び出しているからです。

この部分、直感的にはわかりにくいかもしれませんが、以下のコードに置き換えてみると多少はわかりやすいかもしれません。

swift

1 @objc func timerInterrupt(_ timer: Timer) { 2 3 count += 1 4 5 let retVal = displayUpdate() 6 if retVal <= 0 { 7 // 以下略 8 } 9 }

書籍の例だと、関数(メソッド)呼び出しのあと、そのメソッドの返り値が0以下か否かを直接判定しています。

書き換えた例だと、一旦retValに代入し、それを比較しています。

両方とも本質的な結果は同じですので、まずは直感的だと思う方で理解してみてはいかがでしょうか。

#追記

1つ疑問に感じたのですが、scheduledTimerメソッド単体では、呼び出すメソッドを設定した間隔で無限に呼び出し続けるといった認識で合っているのでしょうか?

(だから他で条件を設定して止めてあげるといった感じで..)

これは、scheduledTimer()メソッドの呼び出し時に指定します。

どのように指定すればいいかというと、それはオンラインヘルプに載っています。
Xcode を使って、scheduledTimer()のところでOptionを押しながらクリックしてみてください。
すると、下記のようなヘルプが出てくるはずです。

いちばん最後の引数にtrueを指定していますが、trueを指定すると連続呼び出しになります。一方、falseを指定することで単独(ワンショット)の呼び出しとなります。

ちなみに、書籍の254ページ「6-2タイマーをスタート」のところにも記載されていますので、合わせてご参照ください。

お使いの書籍はOptionキーを押しながらヘルプを出す方法が書いてありますし、それ以外のXcodeの便利な使い方が詳しく書いてあります。私もこの書籍でかなり使い込めるようになりました。
これらの操作はかなり便利なので覚えておいて損はないと思います。

投稿2020/04/11 01:33

編集2020/04/11 03:13
TsukubaDepot

総合スコア5086

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

tatuya51

2020/04/11 02:13

ソースコードの件、失礼いたしました。 print(#function)を使用し流れを可視化することができ大変参考になりました。 ご回答いただいた内容についてもとてもわかりやすく解決いたしました。 ありがとうございました。 1つ疑問に感じたのですが、scheduledTimerメソッド単体では、呼び出すメソッドを設定した間隔で無限に呼び出し続けるといった認識で合っているのでしょうか? (だから他で条件を設定して止めてあげるといった感じで..)
TsukubaDepot

2020/04/11 03:13

本文に追記しましたのでご参照いただけますでしょうか。
tatuya51

2020/04/11 04:08

理解できました。 ご丁寧にありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問