Swift Playgroundsで学ぶiOSプログラミング

新機能ステップ動作はprint()を併用すると効果的

文●柴田文彦 編集●吉田ヒロ

2016年12月05日 17時00分

ステップ動作の基本

 Swift Playgroundsに備わったステップ動作機能は、少なくとも今のところかなり単純なものです。操作は、これまでの「Run My Code」の左側に配置されたストップウォッチアイコンの中に集約されています。そこをタップすると、プログラムを動作させる際のオプションとして、デフォルトの「Run My Code」も含めて、「Step Through My Code」と「Step Slowly」の3つから選べるようになります。

「Run My Code」ボタンの左に配置されたストップウォッチボタンをタップすると、ステップ動作のオプションが選べます

 言うまでもなく「Step Through My Code」と「Step Slowly」を選ぶとステップ動作になります。実はこれらは実質的には同じものです。違いは、ステップ動作の際の速度、つまり次のステップを実行するまでの待ち時間だけです。もちろん「Step Slowly」の方が待ち時間が長く、そのぶんゆっくり動作することになります。

 このメニューからどれかを選ぶと、その時点でその選択に従ってプログラムの動作が始まります。その後は、選んだ動作がメインの動作ボタンに置き換わります。これにより、以後はステップ動作を1タップで実行できるようになるわけです。

メニューで選んだステップ動作が、これまでの「Run My Code」ボタンを置き換え、1タップでステップ動作が可能になります

 ユーザーが可能な操作はこれだけです。一般的なIDEのステップ動作では、1ステップ実行するたびにプログラムは停止し、その時点での変数の値や、プログラムの内部状態などをかなり詳しく観察できるのですが、今のところそのような機能はありません。また、一般のステップ動作とは異なり、一定時間経過後には自動的に次のステップに移行してしまいます。今のところ停止した状態で詳しく調べるための機能がないので、そうした動作も当然かもしれません。

 それでは何も調べられないかといえば、そんなこともありません。ステップ動作の中で変数の値がどのように変化していくかを、必要に応じて確認することが可能です。その方法については、少し後で示します。

 ステップ動作中は、実行しているソースコードの行がハイライト表示されます。それによって、条件分岐などがある場合に、どのような動きになっているのかを、把握することができます。

プログラムをステップ動作させると、実行中の行がハイライト表示され、その左端には「>」マークのインジケーターも表示されます

素数を求めるプログラムを作る

 今回は、二重ループを使ったプログラムの動きをステップ動作機能を使って観察する例を示します。観察の対象となるプログラムとしては、指定した範囲の整数から素数を抽出するものを取り上げます。素数については中学校の数学で学ぶと思いますが、定義は「その数自身と1以外に約数を持たない自然数」ということになっています。要するに割り切れない数のことです。

 素数は現在のコンピューターによる暗号の基礎となる重要な数です。ここでは定義に忠実な簡便な方法で、ある数が素数かどうかを調べ、素数であればそれを表示します。最初に調べる最大値を入力し、2からその数までの間の自然数を1つずつ順番に調べます。1は素数ではないことになっています。

var maxVal = askForNumber("調べる数の最大値")

for i in 2 ... maxVal {
 var divisor = 0
 for j in 2 ... i {
  if i % j == 0 {
   break
  }
 }
 if divisor == i {
  show(i)
 }
}

 これだけで本当に素数かどうか分かるのかと疑われそうな簡単なプログラムですが、もちろんちゃんと動きます。ただし、プログラムを短くすることを最優先に書いているので、動きに無駄な部分があります。その点には今回は目をつぶってください。探究心のある人は、どのあたりが無駄で、どうすれば改善できるのか考えてみましょう。ちょっとの工夫で少なくとも2倍の効率にできることをヒントとして示しておきます。

 二重のforループについても、ifによる分岐も、この連載ですでに取り上げていますが、これまでにまだ出てこなかった要素が2つあります。それらについて説明しながら、このプログラムの流れをざっと解説しておきましょう。

 まず内側のループの中のifの条件式にある「%」記号です。これは「剰余算」を表します。割り算の一種ですが、その商ではなく余りを求める演算です。例えば「7÷3」という割り算を考えましょう。この商は2、余りは1となりますね。このとき「7 / 2」は商を求めるので、結果は2になりますが、「7 % 2」は余りを求めるので結果は1になります。

 上のプログラムで「if i % j == 0」と書いているのは、i÷jの余りが0かどうかを調べています。余りが0なら割り切れたことになるので、iは素数ではないとわかります。

 もう1つは、そのif文の中の「break」という命令です。これは、それを含むループの実行を中断して、そのループの外に出るというものです。iの約数が1つでもみつかれば、iは素数ではなく、それ以上調べる必要はないので、カウントjによる内側のループを中断しているのです。

 その後、内側のループの中でjの値を代入しておいた変数divisorの値が、外側のループをカウントするiの値と一致するかどうか調べています。これによって、breakによって途中でループを抜けたのか、jを最後まで調べたのかを判断しています。もしbreakによって抜けたとすれば、iがjで割り切れた場合なので、そのときのiは素数ではありません。jを最後まで調べてループを抜けたのなら、そのときのiは素数です。そこで、その場合だけ、show(i)として、iの値を画面に表示しているのです。

 ところで、このようにわざわざdivisorという変数を使って、jの値を保存しておかなければならないのはなぜかと思われるかもしれません。その理由は、Swiftの場合、ループをカウントする変数(この場合はi)は、ループを抜けたとたんに消失してしまうからです。

 最初のaskForNumber()に対してたとえば30と入力して実行すると、30までの素数が順に表示されます。

指定した最大値までの素数を見つけるプログラムを、最大値に30を指定して動かしました

二重ループをステップ動作でデバグする

 上で示した素数を抽出するプログラムの動作は、それほど複雑ではありませんが、その動きをステップ動作で確認してみましょう。二重のループになっているので、最初に示したステップ動作の例のように、実行部分がハイライトされるだけでは動きがよくわかりません。ここは、2つのループ変数、iとjの値の変化を把握したいところです。

 そこで、内側のループの中で、iとjの値をprint()ファンクションを使って表示させてみましょう。以下のような行を挿入します。

print("i = ", i, " j = ", j)

 このような行を入れても、ステップ動作させないと、最終的なiとjの値しか表示されないので、まったく意味がありません。しかしステップ動作にすれば、比較的ゆっくりと動作し、それでいてprint()の結果はその都度更新されるので、動作中の変数の値の変化を確実に知ることができます。

プログラムの途中にprint()を入れることで、ステップ実行中の変数の値の変化がわかるようにしています

 これは変数の値の変化としては単純な例ですが、同じ要領で、どのような変数の値の変化も、プログラム実行中にその場で知ることができます。print()の結果表示の吹き出しに表示される「Add viewer」をタップすれば、ソースコード中に変数の値を常に表示する枠を配置できるので便利です。Swift Playgroundsではほとんど意味がないと思われたprint()も、ステップ動作と組み合わせると、大きな意味を持つことがわかりました。

次回の予定

 今回も含めて3回に渡って利用してきた「Answers」のテンプレートでは、基本的にask()とshow()、そしてそのバリエーションが使えるだけでした。とりあえずそれらも使い尽くした感があるので、次回からは別のテンプレートを選んで作ったプレイグラウンドの機能を探っていくことにしましょう。「Shape」を使えば、いろいろなグラフィック機能が使えるようになるので楽しそうです。

mobileASCII.jp TOPページへ

mobile ASCII

Access Rankingアクセスランキング