OSX
Cocoa
入門
Swift

"Your First Mac App" Swift版

More than 3 years have passed since last update.

Swiftの勉強に Mac Dev Center で公開されているチュートリアル「About Creating Your First Mac App」を Swift でやってみた。

環境は Yosemite + XCode6.1。チュートリアルは XCode4.4 で書かれたもので、進めていくうえで ObjectiveC と Swift の違いより、XCodeの違い(といっても主に見た目の違いだけど)の方に戸惑うことが多かった。所要時間は1時間ぐらい。

以下、チュートリアルを進めていくうえで気になったり、引っかかった点。

  • XCode6.1 では、デフォルトの View の設定が storybord 利用したものに変わっている。テキストボックスやボタンといったコントロールは Window Controllerではなく、View Controller の方に貼り付けていく。各コントロールの属性設定はチュートリアルと変わらない。

  • チュートリアルでは AppDelegate に対して、IBOutlet や IBAction を追加していくというスタイルになっているが、XCode6.1 では ViewController に追加していくのが標準のようだ(ここら辺まだ良くわかっていない)。常識的に考えてチュートリアルのように AppDelegate に記述していくより、ViewController の記述していく方が全うに思えるので、今回はあまり深く考えず ViewController に対してコードを追加していくことにしたのだが、これで良いんだろうか? IBOutlet や IBAction の接続方法もチュートリアルとほぼ変わらない操作で可能だった。

  • チュートリアルで Track モデルのクラスを作成する箇所、チュートリアルではファイルの新規作成で Objective-C class のテンプレートを選ぶようになっているのでが、今回は switft なので Swift file のテンプレートを選択した。でも、ここは Cocoa Class テンプレートを素直に選択すれば良かったようだ。Cocoa Class テンプレートを選ぶとファイルを作成する前にクラス名、ベースクラス、使用言語を指定するダイアログが表示されて雛形を自動で作成してくれる。

  • 今回、一番ハマった箇所。ViewController (チュートリアルでは AppDelegate)に作成したモデルをメンバとして保持させる箇所。単純に、「var track : Track」と書くと、ViewControler に init() がないと怒られる。どうやら、オプショナルでないメンバ変数を定義しようとすると Swift ではイニシャライザを記述して初期化することが必須のようだ。XCode6.1 の修正指示に従い以下のように記述すると

    required init?(coder: NSCoder) {
        super.init?(coder: coder)
        track = Track()
    }
    

    今度は、

    swift consecutive statements on a line must be separated by ";"

というエラーになる。required というのも良く判らないが、init() ではなく init?() となっているもの良く判らない。とりあえず見よう見まねでベースクラスのイニシャライザを呼ぶつもりコードを書いたのだが、どうやらこういう書き方ではダメらしい。今回、Swift については出たばかりの「たのしい Swift プログラミング」木下誠著 BNN を読んだけなのだが、プログラム未経験者向けの入門書ということで詳しい記述がほとんどない。何が何だかという感じなので、とりあえず今回は、「var track = Track()」と宣言と同時に初期化することで回避した。

というような感じで、とりあえず問題は残しながらもチュートリアルは完了。以下に、ViewController と Track モデルのソースを示す。IBAction takeFloatValueForVolumeFrom の中身はチュートリアルとは少し変えてある。

ViewControler
import Cocoa

class ViewController: NSViewController {

    var track = Track()

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

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

    @IBOutlet weak var textField: NSTextField!
    @IBOutlet weak var slider: NSSlider!

    @IBAction func mute(sender: AnyObject) {
        track.volume = 0.0
        updateUserInterface()
    }


    @IBAction func takeFloatValueForVolumeFrom(sender: AnyObject) {
        if sender as NSObject == slider
        {
            track.volume = slider.floatValue
        }
        else
        {
            track.volume = textField.floatValue
        }
        updateUserInterface()
    }

    func updateUserInterface()
    {
        let volume = track.volume
        textField.floatValue = volume
        slider.floatValue = volume
    }
}
track.swift
import Foundation

class Track
{
    var volume : Float = 5.0
}

初 Swift の印象は、if文の評価式に()がないというのがまだ慣れなくて何だか落ち着かないのと、同じくif文の本体が1行しかなくても{}で括る必要があるのが面倒くさいという感じだろうか。

Swift の細かいところ関しては、12月に出るという「詳細 Swift」荻原剛志 著を待ちかなぁ。


追記
ViewController に追加した Track モデルのメンバ変数 track だけど、var 使って変数にしてるけれど、プログラム中で変更されることはないから、let で定数にした方が良かったかも。