MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSA Developer News[MOSADeN=モサ伝]第349号

2009-07-07

目次

  • りんご味Ruby         第50回  藤本 尚邦
  • 藤本裕之のプログラミング夜話   #163
  • 高橋真人の「プログラミング指南」  第161回

りんご味Ruby   第50回  藤本 尚邦

今回は、既存のiPhoneアプリケーションのプロジェクトに、iPhone RubyCocoaを組み込んでみることにします。例として、iPhoneのサンプルコードの1つViewTransitions をリモートアクセスできるようにしてみましょう。

その前に、前回作った iPhone RubyCocoa のプロジェクトフォルダは使い回すことができるので、再利用しやすいように適当な名前(ここではiphone-rubycocoa-sim とします)をつけてどこかに保存しておいてください。

■ iphone-rubycocoaフォルダのコピー

まず、iPhoneのサンプルプロジェクトViewTransitionsを準備してください。このサンプルは、Xcodeのメニューの「ヘルプ/Xcodeの製品ドキュメント」からダウンロード(といってもすでにローカルのディスク内にあるはず)できます。

準備ができたら、Finderで、ViewTransitionsフォルダの中にiphone-rubycocoa-simフォルダをコピーしてください。

■ rubyとrubycocoaの組み込み (1) — C/Objective-Cプログラム部分

次に、Xcodeで、ViewTransitions.xcodeproj とiphone-rubycocoa-sim/rubycocoa4iphone.xcodeproj の両方を開きます。

まず、rubyを組み込みます。rubycocoa4iphoneプロジェクトウィンドウの右側にある「ruby」グループを、ViewTransitionsプロジェクトウィンドウのViewTransitionsにドラッグドロップします。表示されるダイアログパネルの設定は変えずに、そのまま「追加」してください。

さらに、rubycocoaを組み込みます。「rubycocoa」グループをrubyグループと同様にドラッグドロップして追加します。

これで、rubyとrubycocoaのうち、C/Objective-C で書かれている核心部分が組み込まれました。

■ rubyとrubycocoaの組み込み (2-1) — Rubyプログラム部分

次に、RubyCocoaのRubyプログラム部分やremote-irbなどのrubyライブラリを組み込みます。rubycocoa4iphoneプロジェクトウィンドウの右側のResourcesグループから、以下の3つ:

・main.rb
・rubycocoa.rb
・utils

を、ViewTransitionsプロジェクトのResourcesグループにドラッグドロップします。さきほどと同様、パネルの設定は変えずそのまま追加してください。

ここまで完了した時点で、以降の作業では rubycocoa4iphone プロジェクトは使わないので閉じておくとよいでしょう。

■ rubyとrubycocoaの組み込み (2-2) — ビルドフェーズの追加

最後にrubyの添付ライブラリを組み込みます。rubyのライブラリを正しく動かすためには、ディレクトリの階層構造を保ったままコピーする必要があります。Xcodeで階層構造を保ったままコピーするより良い方法がわからなかったため、ここでは、ビルドフェーズで実行されるスクリプトとして組み込むことにします。

ViewTransitionsプロジェクトウィンドウを選んでおき、プロジェクトメニューの「新規ビルドフェーズ/新規スクリプト実行」コマンドを実行して、以下の1行のスクリプトを設定してください。

cp -R iphone-rubycocoa-sim/ruby/lib $BUILT_PRODUCTS_DIR/$PRODUCT_NAME.app/

■ main.m の変更

あとは、main.rb の Rubyプログラムが実行されるように main.m を変更すればすべて完了です。main.m を以下のように変更してください。

#import 
#import "RBRuntime.h"
int main(int argc, const char *argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
int ret = RBApplicationMain("main.rb", argc, argv);
[pool release];
return ret;
}


元の main.m との違いは、RBRuntime.h を import していることと、UIApplicationMain の代わりに RBApplicationMain を読んでいることの2点だけです。UIApplicationMain は、main.rb の中で、remote_irb を起動したあとに呼ばれます(main.rb を見てみてください)。

■ ビルド

ではビルドしてみましょう。困ったことに、29個の警告と2個のエラーが発生してしまいました。ViewTransitions は iPhone Simulator 3.0 向けなので、2.2.1 をベースとした iPhone RubyCocoa ではエラーが発生してしまったわけです。

これらの警告やエラーのほとんどは、自動生成された Objecitve-Cコードである rb_Foundation.m の中で、廃れつつあるAPIを使っていることに起因しているのですが、とりあえず警告は無視します。2つのエラーは、完全に廃れた定数(NSDateFormatterBehavior10_0, NSNumberFormatterBehavior10_0)のRuby側インターフェースを定義しようとして発生しています。この定数はなくても良いので、それぞれの行(rb_Foundation.mの338行目と1554行目、をコメントアウトしてください。

では、ふたたびビルドしてみましょう。今度はリンクでエラーがでました。エラーの原因になっている_NSConstantStringClassReference という値も、ここでは不要なので、rb_Foundation.m から関係する関数を削除してしまいます。

コメントアウトする部分をまとめると以下の4カ所になります:

・rb_Foundation.m 338行目、NSDateFormatterBehavior10_0 の定義
・rb_Foundation.m 1554行目、NSNumberFormatterBehavior10_0 の定義
・rb_Foundation.m 2288行目、_NSConstantStringClassReference の定義
・rb_Foundation.m 2241-2246行目、osx__NSConstantStringClassReference

再度、ビルドしてみしょう。今度はビルドに成功するはずです。

■ リモートアクセス

では、iPhone Simulator で ViewTransitions を走らせて、telnetでリモートアクセスしてみましょう。

 $ telnet localhost 6000
 Trying ::1...
 Connected to localhost.
 Escape character is '^]'.
 >> app = OSX::UIApplication.sharedApplication
 => #
 >> app.delegate.nextTransition(nil)    # アクションを実行
 => nil
 >> app.delegate.performTransition      # アクションの中身を直接実行
 => nil


nextTransition は、UI上にただ一つ存在するボタンから接続されているアクションです。performTransition はnextTransition から呼ばれて実際のtransition を実行します。どちらも ViewTransitionsAppDelegate.m で定義されています。

このように、Objective-Cで書かれたiPhoneアプリケーションのプロジェクトにiPhone RubyCocoa を組み込むことにより、状態の確認や操作などの試行錯誤的作業を、アプリケーションを実行させたまま出来るようになります。

今回紹介した方法は、他のサンプルプロジェクトやXcodeのプロジェクトテンプレートで生成したプロジェクトについても、おおよそ同様の手順で組み込むことができるでしょう。

藤本裕之のプログラミング夜話 #163

 前回の続き、なぜ日本のソフトウェア産業では「人月の神話」がまかり通る……言い換えればプログラマの売り物である「技術」(オレを含めプログラマ自身はこれこそ自分の売り物だと思ってるはずだ)ではなく「人月」というカタチの「時間」を売るのであろうか。

 ……いきなり手前味噌な話を始めてマコトに恐縮なのだが、ワタシが以前書いた「プログラマを笑え!」という本の中に以下の如きくだりがある。ちょい長くなるが引用するね。

 他の業界は知らずこのソフトウェア業界の営業パーソンたちは、まずソフトウェアに関する商品知識を培おうとしないどころかそれが持てないからこそオレは営業をやっているんだとうそぶくようなヤツが一般的であり、かつ業界動向なんてモノにもほとんど興味がない、のである。
 特にソフトウェアの受託開発をするような会社において、営業に商品知識がないということ、すなわち自分トコのプログラマたちの腕とコストを把握していないというのは致命的なことである。誰が考えたってわかる理屈だろう。「高いモンを安く売ってしまう」かも知れないからだ。
 ところがである。不思議なことにこの業界においては、安いものを高く売ろうが高いものを安く売ろうがとにかく営業は売れば褒められることになっており、その仕事が赤字になった責任はすべて実作業を行うプログラマ側が負わされるのである。いや、他の業界のヒトはそんな馬鹿なと思うだろうがそうなのだ。

 5年ほど前の本だけどさして状況は変わってない。つうか、オレがこの業界にはいった1983年、あるいは前回紹介した「人月の神話」が出版された1975年からこのアタリの事情はぜーんぜん変わってないでしょ。

 図らずもこの文中でオレが喝破しておるように、つまるところこの業界が「技術」の代わりに「時間」を売るのは、「売る仕事」をしている連中が「技術」の価値を評価できないからなのである。もっとわかりやすく言えば八百屋のおやっさんが、旬のモノだろうとハウス栽培だろうと有機農法だろうと農薬びしばしの中国産だろうとええいかまうもんかオレに区別がつかないんだから客にも区別なんかつくもんか、とにかくオレが売るネギはどんなネギでも1本50円だぁ、と言って売っちまってるようなものなのだ。

 で、最も大きな問題は上の啖呵のなかにある「オレにも区別がつかないんだから客にも区別なんかつくもんか」というのが、恐ろしいほど正鵠を衝いていることなんだよね。

 一昨年(もう一昨年なんだよね)、いわゆる「宙に浮いた年金問題」が明るみに出たとき「コンピュータ上での照合に必要なプログラムの開発費用」として厚生労働省がNTTデータに払った金額を憶えておいでだろうか? 10億円である。あのあとオレんとこにも「ねんきん特別便」ちうのが来たが、あれに記載されているくらいのデータの類似レコードを抽出してひとまとめにするくらいのプログラム、そーんなに難しいと思いますか? オレもそうだが「1億くれたら、いや5千万でも喜んでやります」ってヒトが多いんぢゃない?

 こういうことを言うと、かならず「それは違う、おっきな会社はその仕事に対する責任も含めて巨額の費用をもらうのだ」とか眠たいこと言うオッサンがいるんだが、責任なんて取ってないぢゃん。年間650億もかかってる年金記録システムが、名寄せ失敗データを10年間も放置してきた結果の問題を修正するために、あらためて10億もらっておいて「責任」なんておこがましいだろ。

 おっと、怒りのあまり話が逸れた。結論として、売り手(この産業における営業パーソン)も買い手も、ソフトウェア(とその開発作業)の価値をキチンと評価できないから、ジッパヒトカラゲ(人月)に、そしてブランド(あれはNTTデータだから10億なのだ)重視でペイメントが決められるのである。
                       (以下次回 2009_07_03)

高橋真人の「プログラミング指南」第161回

これから始めようとする人へ(12)

 皆さんこんにちは、高橋真人です。今回はリファレンスカウントについての説明をしていきます。
 では、以下のサンプルコードをご覧ください。(実際に動かしてみたい方のための説明が記事末尾にあります)

#include 
#include 
#include 

#define LIST_LENGTH 20

typedef struct {
  char name[50];
  int age;
} Person;

void make_list(Person *list[]);
void print_list(Person *list[]);
void clear_list(Person *list[]);

int main (int argc, const char * argv[])
{
  srand(7);   // 乱数生成(make_list)のための準備。タネをあえて固定。
  Person *list[LIST_LENGTH];
  memset(list, 0, sizeof(list));

  make_list(list);

  print_list(list);

  clear_list(list);

  return 0;
}


void make_list(Person *list[])
{
  int i;
  for (i = 0; i < LIST_LENGTH; ++i) {
      list[i] = malloc(sizeof(Person));
      if (list[i] != NULL) {
          list[i]->age = rand() % 30 + 20;    // 20〜49の間の乱数
          char buf[BUFSIZ];
          snprintf(buf, sizeof(buf), "Sample name_%d_.", i + 1);
          strcpy(list[i]->name, buf);
      }
  }
}

void print_list(Person *list[])
{
  int i;
  for (i = 0; i < LIST_LENGTH; ++i) {
      printf("[%02d] age: %d, name: %s n",
             i + 1, list[i]->age, list[i]->name);
  }
}

void clear_list(Person *list[])
{
  int i;
  for (i = 0; i < LIST_LENGTH; ++i) {
      if (list[i] != NULL) {
          free(list[i]);
          list[i] = NULL;
      }
  }
}


 分かり易くするために作為的なプログラムですが(笑)、簡単に解説します。
 人の名前と年齢を持った構造体Personを定義し、Person構造体へのポインタを20個保持する配列listを用意します。
 対話的にデータ入力をするのは省略して、単純に乱数を利用して年齢を作り、特に意味のない(だけど、識別だけは可能な)名前としての文字列を格納します。

 実際のところ、この程度のデータ量であれば、あえてポインタの配列にせず、直接Person型を20個格納してしまう配列を作れば充分ですが、そこは、あくまでも説明のための例なので(笑)。
 ここが話のスタートとなるわけですが、このプログラムにおいてはすべてのPersonデータ(のために確保されたメモリ領域)は、それぞれ一カ所からしか参照されていないので、全く問題はありません。シンプルなものです。
 問題は、1つのPersonデータが複数の個所から参照されるところから始まります。まず、上記のシンプルな例をしっかりと把握して、今後の複雑化に備えてください(笑)。

 注:コードを実際に動かしてみないと理解できない人のために。Xcode(3.1)で動かすためには、ファイルメニューから「新規プロジェクト...」を選び、Mac OS XのCommand Line Utilityというテンプレートを選びます。表示されたアイコン一覧の中から、Standard Toolというのを選び、適当な名前(英数字のみの名にしておいた方が無難)を付けて保存します。
 プロジェクトのウインドウが開きます。右側のファイル一覧からmain.cというファイルをダブルクリックして開きます。main.cの中身を上記のサンプルコードとまるごと置き換えてください。
 実行メニューから「実行」(コマンド+オプション+R)を選べば、コンパイル、リンク、実行が一気に行われます。出力結果は、実行メニューの「コンソール」(コマンド+シフト+R)で見ることができます。

 次回への振り:「今回は、これだけなの?」と、まだまだ余裕のある方へ。
上記のプログラムに以下のような処理を加えてみてください。

・20代の人のみを抽出し、別途リストを作る
・リストを年齢順にソートする
・リストを20代、30代、40代に分離し、最初に作ったリストは廃棄する

◇MOSAからのお知らせと編集後記は割愛します◇

 

 MOSA Developer News   略称[MOSADeN=モサ伝]
        配信停止 mailto:mosaden-ml@mosa.gr.jp
 記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
      記事投稿受付 http://www.mosa.gr.jp/?page_id=850
Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
特定非営利活動法人MOSA  http://www.mosa.gr.jp/
Copyright (C)2009 MOSA. All rights reserved.