クリアメモリ

プログラミングやモーショングラフィックス、便利なアプリケーションなど雑多に記録するブログ

【Swift】時計アプリをscheduledTimerで作ってみる

f:id:clrmemory:20170422183237p:plain 

今回はSwift3を使ったCocoaプログラミングで、現在時刻を表示するだけの時計アプリを作成してみようと思います。

 

cocoaプログラミングでは、Timer関数を使用することで簡単に現在時刻を取得できます。

時間だけではなく、日にちや曜日なども取得できるので試してみてください。

 

はじめに

 

今回紹介する方法は、Xcodeで作るMacOSXアプリです。

同じSwiftでもMacアプリとiOSアプリでは、コードが若干変わってくるので注意してください。

 

また、Xcodeのインストールや、プロジェクトの作成については説明しないので、あらかじめインストール・作成しておくようにしてください。

 

 

ではまず、時計を表示するテキスト「Label」をストーリーボードから作成しましょう。

 

ラベルを配置

 

今回作成する時計アプリでは、「年, 月, 日, 曜日, 時, 分, 秒」を表示させるようにします。

 

以下の画像のように、あらかじめ表示される時計の見た目を設定しておきましょう。

 

 

ラベルが配置できたら、これらをViewControllerにアウトレット接続しましょう。

アウトレット接続というのは、ラベルを右クリックしながらドラッグか、controllを押しながらドラッグでコードと接続できるあれですね。

 

 

コードを記述

 

ストーリーボードの準備が整ったので、いよいよコードから実際に時計アプリを完成させましょう。

 

今回重要になるコードは「Timer.scheduledTimer」と「NSCalendar」です。

仕組みがわかってしまえばとても簡単に時間を表示できるので、参考にしてみてください。

 

では、完成したコードがこちらになります。

 

import Cocoa

class ViewController: NSViewController {

    @IBOutlet weak var dateLabel: NSTextField!
    @IBOutlet weak var timeLabel: NSTextField!

    var timeInterval = TimeInterval()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.

        timeCheck()
        _ = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(timeCheck), userInfo: nil, repeats: true)
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }

    func timeCheck(){
        let date = NSDate()
        let calendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
        let component = calendar.components([
            .year,
            .month,
            .day,
            .weekday,
            .hour,
            .minute,
            .second
            ], from: date as Date)

        let weekday: Array = ["日", "月", "火", "水", "木", "金", "土"]

        let year = "\(component.year!)"
        let month = String(format: "%02d", component.month!)
        let day = String(format: "%02d", component.day!)
        let dayOfTheWeek = "\(weekday[component.weekday! - 1])"
        let hour = String(format: "%02d", component.hour!)
        let min = String(format: "%02d", component.minute!)
        let sec = String(format: "%02d", component.second!)

        dateLabel.stringValue = "\(year)年\(month)月\(day)日(\(dayOfTheWeek))"
        timeLabel.stringValue = "\(hour):\(min). \(sec)"
    }
}

 

 

このコードを実行して、実際に完成したアプリケーションがこちらになります。

 

 

 

コードの大まかな流れとしては、

 

1 現在時刻を取得

2 1秒ごとに時間を更新

3 ラベルに取得した時間を表示

4 2に戻る

 

このようにして、1秒ごとに時間を取得しなおしています。

では順に見ていきましょう。

 

コードの解説

 

まずは、先ほど作成したラベルとアウトレット接続した「dateLabel」「timeLabel」です。

年月日曜日までをひとまとめにして更新するようにしてみました。

 

 

続いて、timeIntervalを作成しておきましょう。

後述するTimerで「何秒ごとに更新するか」を指定させるときに使用します。

 

 

viewDidLoadの中では、まずはじめに現在時刻を1度取得しラベルに反映させます。

このようにしないと、scheduledTimerが呼ばれるまで、ラベルに時間が表示されなくなってしまうためですね。

 

Timer.scheduledTiemr

 

Timer.scheduledTimerでは「〇〇秒ごとに〇〇を呼び出す」という内容になっています。

今回の例で説明すると、timeIntervalが1、呼び出すのは「timeCheck( )」です。

 

つまり、「1秒ごとにtimeCheck( )を呼び出す」ということになりますね。

 

 

NSCalendar

 

timeCheck( )では、時刻の取得とラベルへの反映を行っております。

 

NSCalendar.identifier.gregorian はグレゴリオ暦と呼ばれる太陽歴のことで、1年間を約365日にすると言うものです。

正直詳しくは知りませんが、要するに一般的な日付のことですね。

 

 

 

続いては先ほど作成した「calendar」のコンポーネントを設定します。

ここで設定しておくことで、componentから値を引き出せるようになります。

 

 

同様に、weekday( 曜日 )で使用する文字列も設定しましょう。

 

 

曜日をどのように配列から取り出しているかについては、component.weekdayのところで詳しく解説します。

 

時間の取得

 

では、今回の記事のメインとなる時間の取得です。

基本的な動作は同じなので、まず「年」の場合を例にします。

 

component.year

 

このコードを実行することで、calendarを基にした現在の年を取得できます。

これを「"( )“」で囲むことによって、String型として受け取っています。

 

最終的にラベルに表示されるテキストがString型のためですね。

ちなみにyearは、後で同様の処理を行っているので「" “」で囲まなくても動作するのですが、わかりやすいのでこのままにしておきました。

 

時間を取得しているコードの基盤はこのようになっていると考えてください。

 

 

では、monthやdayなどを見てみると、「String(format: XX, XX)」のようになっていると思います。

これは「format: %02d」という記述を追加することで、「1桁の時は先頭に0を追加」させるためです。

 

 

つまり「1 ~ 9」までは「01 ~ 09」になり、10以降は普通に「10…20」と表示されます。

これで桁数によってレイアウトが変わるのを防ぐことができました。

 

 

 

そして、先ほど少し触れた「weekday[component.weekday] -1」です。

名前を変えておけばよかったのですが「先頭のweekdayは配列」「component.weekdayはcalendar.componentの中にあるweekday」になっています。

 

ここで重要なのが「-1」です。

component.weekdayで取得できる値は「1週間の日数」になります。

つまり 1 ~ 7が帰ってくるわけです。

 

一見問題なさそうに見えますが、配列の値は0スタートなため -1 してあげないと曜日にズレが発生します。

 

 

最後にこれまで作成してきた「年月日曜日時分秒」をラベルに反映させます。

 

 

NSTextField.stringValue = “ ラベルのテキスト ”

というように記述することで、コードからラベルの文字を変更できます。

 

 

まとめ

 

今回紹介したコードを使用することで、簡単にMacOSXの時計アプリが完成しました。

 

現在時刻の取得自体の使用頻度はそこまで高くないかもしれませんが、こんなこともできるんだぐらいに覚えていただければ幸いです。

 

 

ぜひ活用してみてください。

ではまた。

新着記事