Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
97
Help us understand the problem. What is going on with this article?
@KikurageChan

Swift4環境でTimerの使い方と挙動を確認してみた

More than 1 year has passed since last update.

はじめに

こんにちは:leaves:
アプリ内で利用する機会はそれほどでもないのですが、定期実行するTimerについて調べてみたのでメモとして書いてみたいと思います。(Xcode: 9.1, Swift:4.0.2)
至らぬ点などコメント頂けたら幸いです。

Timerの基本的な利用

Timerはインスタンス生成即座に起動されるようです。
:warning:ここで注意点なのですが「fire() = 起動」を意味するものではなく、fire()は、Timerインスタンスが破棄されていない状態にて、すぐにスケジューリングしていたメソッドを呼びたい時に使うためのメソッドのようです。

import UIKit

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate), userInfo: nil, repeats: true)
    }

    @objc func timerUpdate() {
        print("update")
    }
}
//5秒間隔で呼ばれる
//5秒後...
//update
//5秒後...
//update
名前 説明
timeInterval ループなら間隔,1度きりなら発動までの秒数
target メソッドを持つオブジェクト
selector 実行するメソッド
userInfo オブジェクトに付ける値
repeats 繰り返し実行するかどうか

Timerをtargetの変数(ここではMainViewController)に保持した場合などの色々なパターンを書いてみたいと思います。

scheduledTimerを利用するパターン

scheduledTimerでTimerを生成した場合は、内部的に現在の実行ループ(通常はメインスレッド)にてスケジュール登録されるようです。

オブジェクトを保持しない

import UIKit

class MainViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        Timer.scheduledTimer(timeInterval: 5,                                         //ループなら間隔 1度きりなら発動までの秒数
                                target: self,                                         //メソッドを持つオブジェクト
                                selector: #selector(MainViewController.timerUpdate),  //実行するメソッド
                                userInfo: nil,                                        //オブジェクトに付けて送信する値
                                repeats: true)                                        //繰り返し実行するかどうか
    }

    @objc func timerUpdate() {
        print("update")
    }
}
//5秒間隔で呼ばれる
//5秒後...
//update
//5秒後...
//update

オブジェクトを保持する

import UIKit

class MainViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate), userInfo: nil, repeats: true)
    }

    @objc func timerUpdate() {
        print("update")
    }

    @IBAction func buttonAction(_ sender: Any) {
        print("invalidate!!")
        self.timer?.invalidate()
    }
}
//5秒間隔で呼ばれる
//5秒後...
//update
//5秒後...
//update
//invalidate!!
//.......

変数を保持しておくことでinvalidate()でタイマーを破棄することができ、実質タイマーが停止します。
:warning:Timerインスタンスは破棄されるので、同じインスタンスでの再開は不可能です。再開する場合は破棄した時点の時間を計算するなど、Timerインスタンスを生成し直す必要があります。


変数に対して、重ねてscheduledTimerをした場合

import UIKit

class MainViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate), userInfo: nil, repeats: true)
        print(self.timer)
        self.timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate2), userInfo: nil, repeats: true)
        print(self.timer)
    }

    @objc func timerUpdate() {
        print("update")
    }
    @objc func timerUpdate2() {
        print("update2")
    }

    @IBAction func buttonAction(_ sender: Any) {
        print("invalidate!!")
        self.timer?.invalidate()
    }
}
//Optional(<__NSCFTimer: 0x1c017c500>)
//Optional(<__NSCFTimer: 0x1c017e600>)
//5秒後...
//update
//update2
//5秒後...
//update
//update2
//invalidate!!
//5秒後...
//update
//5秒後...
//update
//invalidate!!
//5秒後...
//update

内部的に実行ループに登録されるようで、2回目の上書きでも、invalidate後に1回目で生成したTimerが呼び出されてしまいます。

Timer.initを利用するパターン

イニシャライザでTimerを生成した場合は、自ら実行ループ(通常はメインスレッド)にスケジュール登録をする必要があります。

import UIKit

class MainViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.timer = Timer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate), userInfo: nil, repeats: true)
        //登録
        RunLoop.main.add(self.timer!, forMode: .defaultRunLoopMode)
    }

    @objc func timerUpdate() {
        print("update")
    }

    @IBAction func buttonAction(_ sender: Any) {
        print("invalidate!!")
        self.timer?.invalidate()
    }
}
//5秒間隔で呼ばれる
//5秒後...
//update
//5秒後...
//update
//invalidate!!
//.......

変数に対して、重ねてinitをした場合

import UIKit

class MainViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        self.timer = Timer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate), userInfo: nil, repeats: true)
        self.timer = Timer(timeInterval: 5, target: self, selector: #selector(MainViewController.timerUpdate2), userInfo: nil, repeats: true)
        RunLoop.main.add(self.timer!, forMode: .defaultRunLoopMode)
    }

    @objc func timerUpdate() {
        print("update")
    }
    @objc func timerUpdate2() {
        print("update2")
    }

    @IBAction func buttonAction(_ sender: Any) {
        print("invalidate!!")
        self.timer?.invalidate()
    }
}
//5秒間隔で呼ばれる
//5秒後...
//update2
//5秒後...
//update2
//invalidate!!
//.......

こちらは上書きされた後に自らケジュール登録をしたので、2回目のTimerのみが呼ばれます。

タイマーが呼ばれているタイミング

iPhone

ホームボタンを押して、アプリがバックグランドになると、タイマーのメソッド呼び出しが止まり、再びアクティブになると呼び出しが戻るようです。

AppleWatch

digital crownを押してHomeに戻っても、Timerは呼ばれ続けるようです。任意で止めたい場合はwillActivate()didDeactivate()でコントロールする必要があるみたいです。

参考にさせていただいた記事

見て頂いてありがとうございます。

97
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
KikurageChan
見て頂いてありがとうございます。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
97
Help us understand the problem. What is going on with this article?