Swiftを使って初めてMacアプリを作ってみた

広告

昨年からSwiftをやるやる詐欺をしていましたが、ようやっとやってみました。

Apple関係は、以前に簡単なiPhoneアプリを作ってみた(phpでいうと、file_get_contentsとしてpreg_replaceしてechoするだけ)のですが、1日程度かかってようやっとできたけど、Objective-Cは好きになれないと思ったレベルです。

まずは初心者のためのSwiftプログラミング入門のページを半日ほどかけて読んでPlaygroundで試してみて、なんとなくObjective-Cよりかは取っつきやすいかなと思ったのでやってみました。
BlackBerryアプリ、Objective-Cの時と同じで、何事もとりあえずやってみないとね。

今回は、ちょうどこの間Automaterで作った「iPhone画像を日付別に振り分ける奴のアプリ版」が手軽でちょうど良いかなと思いましたので作ってみることにします。
 

◎ まずは仕様決め


仕様は以下のようにしました。
1. Exif情報で撮影日を取得→取得できなければファイル更新日を取得
2. Exif情報の中のカメラ名を取得→取得できなければ「No Camera」とする
3. コピーまたは移動ができるようにする
4. コピー先(移動先)には、カメラ名>日付>個々のファイルとなるようなフォルダ構成とする

この間のシェルスクリプトの場合、ファイル更新日での振り分けなので、今回はちょっとだけ厳密にします。
 

◎ 作り始めよう


さてと、とりあえずXcodeを立ち上げプロジェクトを作ります。
そして、MacアプリでSwiftを選びます。
ストーリーボードを使って、部品を配置していきます。
この辺りは以前にObjective-Cでやったのと同じなので、あまり気になりません。

部品を配置

その後は、部品とプログラムを紐付けるために、部品を選択して、controlを押しながらswiftファイル内に配置。

ぐりぐり持っていく

離すと、Outletか、Actionを選択できるので、
変数定義する場合はOutlet、ボタンを押したときの処理はActionを選択
まず、使うパーツはすべてOutletで変数紐付けをして、ボタンなど処理が必要なものに対しては、Actionも定義する感じ。

変数とするか処理とするかを選択

あとは、処理の中をごりごり書いていくだけなのですが……
Swift&Mac OSXのサンプルやページは全然見つからない。BlackBerryの方がまだ見つかるかも。
ほとんどがObjective-C、またはSwift&iOSばかり。
なので、Objectve-Cの書き方を参考にSwiftに置き換えたとき、iOSの書き方を置き換えたときを推測しながらやってみた。
Stack Overflowさまさま。あとQiita。
 

◎ 悩んだところ中心にメモ


- ファイル選択ダイアログ用のコントローラーは無いっぽいので、ボタンなどのアクションでNSOpenPanelを使う。

- try catchは無いのでif letで代用な感じ? よくわからない

- exif情報は、CGImageSourceCreateWithURLでCGImageSourceRefを作る。そのCGImageSourceRefを元に、CGImageSourceCopyPropertiesAtIndexでNSDictionaryを作る。あとは、objectForKeyで必要な情報を抜き出す。import ImageIOも追加
 
var url:NSURL = NSURL(fileURLWithPath: fileUrl)!
//exif情報取得
imageRef:CGImageSourceRef = CGImageSourceCreateWithURL(url, nil)
imageDict:NSDictionary = CGImageSourceCopyPropertiesAtIndex(imageRef, 0, nil)

var exif: AnyObject? = imageDict.objectForKey(kCGImagePropertyExifDictionary)
var date: AnyObject? = exif?.objectForKey(kCGImagePropertyExifDateTimeOriginal)

- ファイル情報から更新日付を取得するとGMTなので、ローカル時間に合わせる必要がある
 
var format:NSDateFormatter = NSDateFormatter()
format.locale = NSLocale.currentLocale()
format.dateFormat = "yyyy_MM_dd"
                            
if let attr: NSDictionary = NSFileManager.defaultManager().attributesOfItemAtPath(
fileUrl, error: nil) {
    var modified:NSDate = attr.fileModificationDate()!
    var strDate = format.stringFromDate(modified)
}

- xとかで閉じた時にアプリを終了するには、AppDelegate.swiftファイルにapplicationShouldTerminateAfterLastWindowClosedを追加
 
func applicationShouldTerminateAfterLastWindowClosed(theApplication: NSApplication!)
 -> Bool {
        return true
}

- パッケージをエクスポートするには、Product-Archiveから行う。

Xcodeがちょこちょこ直してくれるから、思い通りには動いてくれたけど、いまいちよくわかってない。
 

◎ 理解不能…


未だに理解できない点は、
- !や?を付ける場合と付けない理由

- 関数呼び出すときに、2個目以降にはx:xを付ける
例えば、filecopy(a, b, c, d, e)と呼び出すときに、filecopy(a, b:b, c:c, d:d, e:e)としないと怒られる。
filecopy(a:a, b:b, c:c, d:d, e:e)ならまだ理解できるけど、なんで2個目以降だけ必要なのか。
 

◎ Swiftの感想


- Objective-Cよりは好きだけど、サンプルが少ないのが難点。

- もう2,3個作ってみないと何とも言えないかな。

- Macアプリだとデベロッパー登録しなくても良いのでうれしい。
配布する予定があれば登録するけど、自分用なのにお布施は辛い。
個人的にはiPhoneもそうあって欲しい…

- 2日間でできたから思っていたよりかは時間がかからなかった。
慣れればもっと早くできそう。

- Swiftの方がObjective-Cより疲労具合も少ないから良いかも。
 

◎ 最後に完成したアプリ


最後に、今回作ったアプリの動作はこんな感じ
ファイル一覧
テスト用にWebから拾ってきた画像が格納されています。

こんな感じで実行
今回作ったアプリを立ち上げてフォルダを選択。
画像が入っているフォルダと格納先フォルダを指定。
今回は両方同じ。

振り分け完了
あっという間に完成
フォルダや画像ファイル以外は除外

ちゃんと分けられてる
ちゃんと分けられた。わーい。
Automaterのより処理が早い感じがする。

楽しかった。次回は何を作ろうかな。