Timer サンプルを読む

なかなかアクティベートされなく、手持ち無沙汰なのでとりあえずサンプルを読んでみる(https://github.com/HipByte/RubyMotionSamples)。今日読んだのは Timer というストップウォッチアプリ。実際に動かしていろいろ試しているわけじゃないので、自信がない。

Timer/app/app_delegate.rb

application:didFinishLaunchingWithOptions 起動完了時の動作

UIWindow.alloc.initWithFrame(UIScreen.mainScreen.bounds)

[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

に対応する。

アプリケーションのウィンドウはUIWindowのインスタンスで表現できる。Objective-Cでは[[Class alloc] init]でインスタンスを生成する([Class new]でもOK)。allocでメモリ領域を確保し、initで初期化だが、initは引数を取らない。引数を渡せるイニシャライザが欲しかったら、引数付きのイニシャライザを作る必要がある(指定イニシャライザ)。

initWithFrameでは画面サイズを渡す必要があり、UIScreen.mainScreen.boundsで取得できる。ここで生成したウィンドウにボタン等のビューを追加していく形で画面に表示していく。

@window.rootViewController = TimerController.alloc.init

TimerControllerはUIViewControllerを継承している。UIViewControllerはビューの管理を行う。Viewガイドによれば、ビューは階層構造を持っており、ビューコントローラがビューの表示を行う。ウィンドウはルートビューオブジェクトを1つ持っているので、これを制御する rootViewControlleを設定してあげる必要がある。それにしてもいちいち.alloc.initと書くのは野暮ったい。

@window.makeKeyAndVisible

メインとなるウィンドウを作成して描画する。

ビューコントローラの管理サイクル

Viewガイドによると、ビューの管理ではロードサイクルとアンロードサイクルという2つのサイクルが独立して発生する。コントローラが管理するビューオブジェクトが必要になった時、オブジェクトがメモリ内に存在しない場合にロードサイクルが発生する。

ロードサイクルでは、ビューがメモリ内に存在しない場合、loadViewメソッドを呼び出し、ビューをロードする。ロード時に実行する処理として、viewDidLoadメソッドが読み出される。

メモリ不足によりビューを解放する必要が出てくるとアンロードサイクルが発生する。ロードサイクルと同様に、ビューの開放と開放した後の処理が呼び出される。

Timer/app/timer_controller.rb

viewDidLoad でロード時に実行する処理を記述

UILabelは文字を表示させる時に私用する。UILabelはUIViewを継承しているので @state.frameで位置と大きさを指定できる。このストップウォッチ以外のUILabelの例を見るとCGRectでサイズをしているけど、ここでは配列で指定されている。このメソッドでのviewはビューコントローラが担当しているビュー、即ちウィンドウ。

view.addSubviewでラベルを追加。

setTitleでボタンの文字をセットする。forStateにはUIControlStateを設定する。addTargetでイベントリスナをセットする。1個目の引数がアクションメッセージを送る対象、:actionはイベントが発生した時の処理、:forControlEventsは補足するイベント。

actionTapped

NSObjectはルートクラス。NeXTSTEPの略らしい。@timerが存在していたらタイマーを止めて、自身をnilにする。scheduledTimerWithTimeIntervalの1番目の引数が繰り返しの時間(秒)。

@action.selectedのデフォルトはfalse

timerFired

0.1秒ごとに呼び出される。

String#%でフォーマットされた文字列が返ってくるんですね。知らなかった。

Timer/spec/main_spec.rb

RubyMotionはBaconというテストフレームワークを使用する。まんまRSpec。 UIApplication.sharedApplicationはアプリケーションインスタンスで、今回はウィンドウがひとつであるかを確認している。