S3Sync
以前、S3にバケットを作成してGlacierアーカイブを行う手順を確認したが、この仕組みを利用してMacの任意のディレクトリをS3 Glacierと自動的に同期するアプリケーション「S3Sync」を作ってみた。Macのスリープを検知すると同期を始めるので、寝ている間にラクラク同期できる。
といってもこのアプリ、単にNSTaskを使ってシステムコマンドを実行しているだけのアプリなので、任意のコマンドを自由に実行することができる。ステータスバーに常駐しているアプリなので、作業の邪魔にもならない。

スリープ検知
スリープ検知をするには、NSWorkspace ClassのNSWorkspaceWillSleepNotification属性を使う。
func applicationDidFinishLaunching(aNotification: NSNotification) {
// スリープ検知
NSWorkspace.sharedWorkspace().notificationCenter.addObserver(self, selector: #selector(self.receiveSleepNotification(_:)), name: NSWorkspaceWillSleepNotification, object: nil)
}
func receiveSleepNotification(notification: NSNotification){
// スリープ実行時に行う処理
}
システムコマンドの実行
システムコマンドは、NSTask Classから実行することが可能である。
NSTaskは、実行したシステムコマンドの出力結果を取り出すことも可能だが、readDataToEndOfFile()を使うとブロッキング処理が発生してしまうので、dispatch_async()を使って非同期に順次出力処理していく必要がある。
let task = NSTask()
// 実行コマンドをフルパスで指定
task.launchPath = "/usr/local/bin/aws "
// パラメータを配列形式で指定
task.arguments = ["-h", "hogehoge"]
// 標準出力をパイプに渡す
let pipe: NSPipe = NSPipe()
task.standardOutput = pipe
let stdoutHundle = pipe.fileHandleForReading
// 非同期処理
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), {
var dataRead = stdoutHundle.availableData
while(dataRead.length > 0){
let stringRead = NSString(data: dataRead, encoding: NSUTF8StringEncoding)
if let output = stringRead {
// 出力結果処理
}
dataRead = stdoutHundle.availableData
}
// コマンドの実行
task.launch()
NSTaskは、suspend()やterminate()を使って、途中で処理を停止したり、完全に終了してしまったりすることができる。suspend()で中断した処理は、resume()で再開することができる。また、タスクが実行中にも関わらず再度launch()を実行してしまうと、下記の実行エラーが発生してしまう。
task already launched
通知の送信
本アプリは、コマンド実行毎にMacの通知センターに実行状況を通知する。

Macの通知センターに通知を送信するには、NSUserNotificationCenter Classを使う。送信する通知には、「タイトル」「サブタイトル」の他に様々な項目を設定することが可能である。
// NSUserNotificationCenterDelegateが必要
class AppDelegate: NSObject, NSApplicationDelegate, NSUserNotificationCenterDelegate {
func deliverNotification(title : String, subtitle : String, informativeText: String){
// AppDelegate Classにデリゲードを指定
NSUserNotificationCenter.defaultUserNotificationCenter().delegate = self
let notification = NSUserNotification()
notification.title = title
notification.subtitle = subtitle
notification.informativeText = informativeText
notification.contentImage = NSImage(named: "MainIcon")
notification.userInfo = ["title" : "タイトル"]
NSUserNotificationCenter.defaultUserNotificationCenter().deliverNotification(notification)
}
}
ログを保存するディレクトリの指定
本アプリは、実行ログをファイルに保存することができる。

Macでディレクトリやファイルを開くする際は、NSOpenPanel Classを利用する。
また、保存の際はNSSavePanel Classというクラスも用意されている。
// MARK: ディレクトリ選択画面
let panel = NSOpenPanel()
// ファイル選択の可否
panel.canChooseFiles = false
// ディレクトリ選択の可否
panel.canChooseDirectories = true
// 複数選択の可否
panel.allowsMultipleSelection = false
panel.beginWithCompletionHandler({(num) -> Void in
if num == NSModalResponseOK {
// ディレクトリ・ファイル決定時の処理
}
})
常駐アプリ
ステータスバーに常駐するアプリを作成するためには、Project > TARGET > Info > Custom OS X Application Target Propertiesから、Application is agent (UIElement)をYESに設定する。

StoryBoardのTips
- 常駐アプリであっても、Main Menu > Edit がないと、TextFieldの Shortcut Keyが使えない。



