2014年11月15日土曜日

iOS実験専用アプリを活用しよう(3)

iOS実験専用アプリを作って活用する話の続きです。前回は、簡単な機能の実験を取り上げました。続きとして、もう少し複雑な機能を作るときの注意点を解説します。今回のswiftコードも、一部を除いてViewControllerクラスに入れます。

 

各ボタンに用意してある2つの関数のうち、多くのコードを追加するのは、タップされたときに動かすほうの関数(名前がtestで始まる関数)です。行数が多くなると困るのが、機能をオフする場合。全体を囲むコメントで何とかなりますが、2カ所の入力が必要で、使いやすくはありません。やっぱり、オフする際には1行だけコメントに切り替える方法(2つの半角スラッシュ)が一番です。

1行だけでオンオフする方法としては、return文を追加する手も使えます。実行したいコードの先頭にreturn文を入れ、それをコメントにすると以降が実行されるという具合に。逆に、return文をコメントでなくすると、オフの状態という使い方です。ただし、return文が使える状態では、コンパイラーから注意が出てしまいます。return文以降が絶対に実行されないよ、という注意で、例の黄色い表示です。気分が良くないので、使いたくないのが普通でしょう。

これらとは違う方法を採用します。ボタンに追加する機能が2行以上になるときには、それ全体を関数として外に出します。ボタンのタップで起動する関数内では、外に出した関数を呼び出す形にします。こうすると、呼び出す部分が1行になり、、機能のオンオフが簡単になります。具体的なswiftコードは、機能をオフした状態では次のようになります。

// ボタンタップで動作する機能を関数として外に出し、それをオフした状態
// ====================================== ボタン15
func startBtn15F() {
    aryButton[15].setTitle("x総数計算", forState: .Normal)
}
func testBtn15F(rSender:UIButton) {
    setMsgF(1, "タップ15")
    //run15F() // <------------------------ コメントにしてオフ状態
}
func run15F() {
    ...
    getTotal15F()
    ...
}
func getTotal15F() {
    ...
}
// ====================================== ボタン16

ここで大事なのは、追加した関数名です。他の機能と関数名が重複しないように、関数名の一部にボタン番号を必ず入れます。ボタン15に追加する機能の場合なら、関数名を「run15F」や「getTotal15F」にするといった具合に。このようにルール化しておけば、関数名の重複を気にする必要がなくなります。

もちろん、例外もあります。作り終わったとき、関数をそのまま持っていけるように作りたい場合もあるでしょう。そんなときは、最終的に使う関数名を付ます。当然、関数名が重複しないように注意しながらですが。

 

作る機能が複雑になるほど、関数の外に変数を用意する必要性が増します。変数を使う場合も、簡単な注意点があります。まず変数名ですが、関数名と同じように、ボタン番号を必ず含めます。このルールに決めると、変数名の重複を気にする必要がなくなります。

次に変数宣言の挿入場所です。追加する機能だけで使う変数ですから、関係する関数の近くが最適です。これも自分なりのルールを決めたほうがよいでしょう。私の場合は、最初に用意された2つの関数よりも前に置くと決めています。最初に変数宣言があれば「この機能は、関数の外に出した変数を使っている」と気付きやすくなるからです。とにかく、自分の好みのルールで統一することが大事です。

私のルールで作った場合の具体的なswiftコードは、次のようになります。

// 関数の外で変数を使う場合の例
// ====================================== ボタン16
var iAVPlayer16:AVAudioPlayer!

func startBtn16F() {
    aryButton[16].setTitle("AIFF再生", forState: .Normal)
}
func testBtn16F(rSender:UIButton) {
    setMsgF(1, "タップ16")
    iAVPlayer16 = playSoundResF("Yen", "aiff", 1.0)
    iAVPlayer16.play()
}
func playSoundResF(rFName:String, _ rSuffix:String, _ rVol:Float) -> AVAudioPlayer {
    var iAVPlayer:AVAudioPlayer!
    let fileURL:NSURL = NSBundle.mainBundle().URLForResource(rFName, withExtension:rSuffix)!
    iAVPlayer = AVAudioPlayer(contentsOfURL:fileURL, error:nil)
    iAVPlayer.volume = rVol
    return iAVPlayer
}
// ====================================== ボタン17

この例のtestBtn16F関数では、コメント化する場合の対象が2行になっています。連続した2行ならコメントに変更しやすいので、わざと残してみました。実験専用アプリですから、ある程度までなら、緩く作っても構わないと思います。

 

画面上にUI部品を追加し、それに値を入れたり参照する場合も、関数の外に出します。置き場所は、変数と同じルールで構わないでしょう。具体的なSwiftコードは、次のようになります。

// UI部品(ここではUITextField)を追加する例
// ====================================== ボタン17
var txfTimeIntv:UITextField!

func startBtn17F() {
    aryButton[17].setTitle("HandCtrl", forState: .Normal) // <----- ボタン名変更もお忘れなく
    txfTimeIntv = createTxtFldF("12", 16, ALIGN_LEFT, 700, 60, 100, 30)
    viewBase.addSubview(txfTimeIntv!)  // <--------- オフするときは、この行をコメント化
}
func testBtn17F(rSender:UIButton) {
    setMsgF(1, "タップ17")
    run17F()  // <--------- オフするときは、当然ですが、こちらもコメント化
}
func run17F() {
    ...
    let iDouble:Double = Double(txfTimeIntv!.text!.toInt()!)
    ...
}
// ====================================== ボタン18

画面上にUI部品を追加した場合も、機能をオフしたいときがあります。そのときは、UI部品の生成はそのままにしておき、ビューに加えている箇所だけコメントにします。具体的には、addSubviewメソッドの箇所だけコメント化するということです。

この方法の利点は、続くコードへの影響がほとんどないことです。UI部品を生成して設定するところまでは残っていますから、そのUI部品を使うコードがコンパイルエラーになることはありません。

 

作りたい機能が大きくなると、独立したクラスとして作る場合もあるでしょう。その際には、追加するクラスを別なswiftソースコードに入れ、そのクラスを利用するコードだけをViewControllerクラスに入れます。

// クラスを使う側のコード(ViewController.swift)
// ====================================== ボタン18
func startBtn18F() {
    aryButton[18].setTitle("HandCtrl", forState: .Normal)
}
func testBtn18F(rSender:UIButton) {
    setMsgF(1, "タップ18")
    run18F()
}
func run18F() {
    let handCtrl = HandController()
    ...
}
// ====================================== ボタン19
// クラスは別なソースコードに分けて追加(HandController.swift)
class HandController {
    ...
}

クラスとして作る場合は、重複しないクラス名を付けるはずですから、ボタン番号を気にしないで付けても大丈夫でしょう。そのクラスを呼び出す関数だけ、ボタン番号を付けることになります。

 

続いて、デバッグ時に役立つ使い方も紹介しましょう。期待したとおりに動かない場合は、どこを通っているか調べたり、途中での値を表示したり、プログラムが動く様子を探ろうとするでしょう。ブレークポイントを設定して動き止め、途中の状態を調べる方法も、よく使われます。

それとは別に、println文を使って、動きの流れを記録したり、途中の変数を記録する方法もあります。println文で出力した内容は、デバッガで見ることになるため、画面の切り替えが生じます。少し手間ですね。その代わりに使うのが、用意したラベルへのメッセージ表示です。setMsgF関数とaddMsgF関数を組み合わせて、通った箇所を表示させます。

具体的な例を見たほうが分かりやすいでしょう。次のようなswiftコードになります。

// 
// ====================================== ボタン20
func startBtn20F() {
    aryButton[20].setTitle("HandCtrl", forState: .Normal)
}
func testBtn20F(rSender: UIButton) {
    setMsgF(1, "タップ20")
    run20F()
}
func run20F() {
    setMsgF(0, "通過:0,")
    ...
    if flagVX {
        addMsgF(0, "2b,")
        ...
        return
    }
    addMsgF(0, "2a,")
    ...
    addMsgF(0, "4,")
    ...
    switch (n) {
    case 1:
        addMsgF(0, "61,")
        ...
    case 2:
        addMsgF(0, "62,")
        ...
    case 3:
        addMsgF(0, "63,")
        ...
    default:
        addMsgF(0, "69,")
        ...
    }
    ...
    addMsgF(0, "9,")
}
// ====================================== ボタン21

かなり入れ過ぎですね。何種類かの例を含めたので入れ過ぎました。実際に使う場合は、適度な数を入れてください。

使い方の基本としては、最初にsetMsgF関数を使い、前の実行で残っている文字列を消しながら、新しい文字列を入れます。それ以降ではaddMsgF関数を使い、文字列を後ろに追加していきます。if文やswitch文のところでは、両方または見たいほうにaddMsgF関数を付けて、どちらに行ったのかを調べます。タップした直後に、動きがラベルに表示されるので、表示を切り替える必要はありません。もしテキスト入力欄を追加し、そこに文字列を入力してはタップするようなテストだと、値によって通る箇所の違いが容易に見えて助かります。

ちなみに、最初に表示するsetMsgF関数にだけ、先頭に「通過」という文字列を入れています。これは、何年後かにソースコードを見たときや動かしてみたとき、「通過した箇所を表示しているのだな」と理解させるためです。「少しの手間で、数年後の自分へ親切にする」という方針の一環です。

 

デバッグ時の途中の値の表示も、同様に簡単です。表示するラベル番号を選び、setMsgF関数やaddMsgF関数を追加するだけです。

// 実行途中の値もラベルに表示
    ...
    setMsgF(4, "iStr=\(iStr)")
    ...
    if (n > 5) { addMsgF(4, ",iStr2=\(iStr2)") }
    ...
 

値の表示でも、できるだけ1行で書くことが大事です。1行だけだと、先頭に「//」を追加してコメントに変更しやすいですから。

私の場合、コメント化した行は、使い終わっても残すようにしています。後から機能を変更したり、再テストするときに、その行が役立つこともあるからです。本番用のソースコードではないので、コードを綺麗に保つ必要はないでしょう。

 

ここまで、実験専用アプリの使い方を詳しく説明しました。いろいろな注意点も細かく取り上げたので、すべて理解すれば、かなりの使い手になると思います。次の投稿では、書き残した点などを書く予定です。

 

(使用開発ツール:Xcode 6.0.1, SDK iOS 8.0)

0 件のコメント:

コメントを投稿