「列車図鑑 九州新幹線 新800系」プロモーションビデオ


電子書籍「列車図鑑 九州新幹線 新800系」の、プロモーションビデオを作成したよ!

For iPhone/iPad

For iPad

他のものと比べても、鉄分が多めのアプリとなっとります。自称、鉄分の補給が必要だ!と思っている方は、ぜひ。

[MandalArt-Dev] iMandalArt HD 1.4に問題あり、1.4.1を申請中


MandalArt-Devです。かねてから告知していましたように、iOS 5に対応すべくiMandalArtとiMandalArt HDの準備を行っています。

iOS 5で動作確認を行ったものをiMandalArt HD 1.4として申請したところ、すでにApp Storeに登場しています。ですが、このビルドはiOS 4で動かそうとする問題があることが発覚しました。具体的には、起動することができません。

この問題の対策を行ったiMandalArt HD 1.4.1を、現在申請中です。iMandalArt 1.4をダウンロードして問題が発生している方は、このアップデートをお待ちください。まだアップデートされていない方は、iMandalArt HD 1.4.1までお待ちください。

ご迷惑をかけて申し訳ありません。

追記:App StoreにiMandalArt HD 1.4.1が登場しました。iOS 4での動作も確認しています。アップデートをお願いします。

あるプログラマとMac OS Xとスティーブ・ジョブズ


ジョブズに思いを馳せていると、彼が自分にどう影響を与えたか、ということに返ってくる。という訳で、めずらしく個人的な話ですが、私のプログラマ遍歴を。

最初に触ったパソコンは、小学生のときのPC-8001でした。ベーマガを見ながら、N-BASICのゲームプログラムを打ち込むという、少年時代を過ごしておりました。その後、PC-8801、PC-8801mkIIFAと順調にステップアップしました。

そして大学生になったある日、がんばってお金を貯めたので新しいPCを買おう、最近よく聞くDOS/Vとかいうのにしてみるかね、というときに出会ったのがMacintosh Color Classicでした。衝撃でした。一目惚れでした。いままでMacのMの字も知らなかったのに、買っちゃいました。そこからApple三昧の日々が始まります。

ワープロ系、ペイント系、ドロー系、DTM系、と一通りのアプリケーションを触った後、むくむくとプログラミング熱が起こってきました。この辺はパソコン少年の名残でしょうか。昔はアプリは使うものではなくて、作るものだったんでね。Macのアプリを作りたい!

HyperCardはいまひとつ性にあいませんでした。おれはスタックじゃなくて、アプリを作りたいんだよ。そこで目をつけたのがCode Warrior。その硬派な名前とパッケージに痺れました。アカデミックプライスがあったのも、学生の身としては嬉しかった。購入して、インストールして、マニュアルに載ってたサンプルプログラムを1行ずつ打ち込みました。終わった!よし実行!すると、ウインドウが表示されました。やった!でも、ドラッグしても動かない!つーか、メニューが変。Appleメニューが2つ表示されている?!つーか、フリーズしてるよ、これ!

昔のMacプログラミングって、ウインドウのドラッグやリサイズも全部自分でコード書かないといけなかったんですよね。そもそも、イベントループも自分で回すし。優美にエレガントに動いているように見えるMac OSも、その裏ではすさまじいベタな努力が積み重なっているのを実感しました。リンゴの魔法が解けた日でした。その日から、私の興味は、一気にシステムの内側に向かっていきます。

始めのMacプログラミングは、うまく進みませんでした。Inside Macintoshやプログラミング本とくびっぴきになりながらコードを打っても、ぜんぜん思い通りに動いてくれない。分かんない、とにかく分かんない。暗中模索、五里霧中、そんな四字熟語がぴったりの状態でした。いまなら理由が分かります。情報系の知識が圧倒的に不足していた事もあるけど、システムがモダンではなかった。Mac OSは、モダンではなかったです。開発者にとんでもない労力を強いるものでした。今思うと、このときもがきまくった苦労は無駄ではなかったです。でも、生産性という視点で考えると、無駄そのものでした。さらにPower Plantとかも登場して、私の混迷はさらに深まります。

鬱々とした状態が続く中、飛び込んできたニュースはスティーブ・ジョブズの復帰とMac OS Xの登場でした。テン?また新しいもの覚えないといけないの?と疑心暗鬼でしたが、とにかく技術仕様書をダウンロードして読みました。衝撃でした。最初にMacと出会ったときから数えて二度目の衝撃でした。Project BuilderとInterface Builderの関係に痺れました。App KitのAPIの美しさにメロメロでした。このとき、ちょうど私は最初の会社に入社したときだったんですが、新人研修中に研修なんか無視して、Mac OS Xの仕様書を読みふけっていました。

それからは、Mac OS Xプログラミング、というかCocoaプログラミングの日々でした。とにかく楽しい。これがその当時の気持ちです。プログラミングの楽しさは、プログラミングそのものにあるのです。美しいフレームワークを触り、その背後にある設計者の思想を読み取り理解する。プログラミングを通して、ユーザと設計者と対話をするのです。

ここまで惚れ込むと、そのさらに後ろにあるジョブズの影も見えてきます。もちろん、ジョブズがCocoaを作った訳ではないです。でも、App KitとFoundationの開発にゴーサインを出し、その価値を認め採用を決定したのは、まぎれもなくジョブズでしょう。ジョブズがCocoaなどのソフトウェア技術にどこまで知見があったのかは私は知りませんが、その本質を見抜く、技術に対する勘があったのだと信じたい。Cocoaには、iMacやiPhoneやiPadと同じ、Apple的美しさがあります。

だから言いたいのです。ジョブズ、ありがとう。他のたくさんのプロダクトともに、Mac OS XとCocoaを作ってくれてありがとう。私はこれを使って、ソフトウェアを作り続けます。

最後に余計な一言。あのとき、Beにならなくて本当によかった。

スティーブ・ジョブズ


仕事をしていると、隣に座っていた女の子が、「えっ」と声を上げた。「これって…」と指差す画面には、白黒のスティーブ・ジョブズの写真と、2つの年号が映っていた。

それが意味するところを悟ると、始めにおとずれたのは衝撃。その後は悲しみ。いつか来るとは分かっていたけど、こんなに早いとは思わなかった。

私個人のジョブズとのつながりなんて、WWDCのステージの上にいたのを遠くから眺めていたくらいしかない。でも、いま私がここで自分でやりたい思ったことを、やると決めて続けていられるのは、すべて彼のおかげだ。

いまは、ただ悲しい。

Xcode 4のメソッド一覧で検索


最近、うちの会社の人から教えてもらった話。

Xcodeのエディタウインドウの上の方に、メソッド一覧をポップアップ表示してくれるボタンがあるじゃない。行きたいメソッドにすぐジャンプできるやつ。これは知ってた。

Xcode 4では、そのポップアップを表示した状態でテキストを入力すると、メソッド名の検索ができる!これは知らなかった!

メソッドがたくさんあるときに便利。最近作っているアプリは、1クラスに数百メソッドはざらなので、とっても便利。

iOS 5 GM遂に登場!


ということで、やっと出てきたiOS 5 GM。絶賛インストール中。

ユーザへの正式公開まで一週間しかないという、相変わらずのタイトスケジュール。今日は、ビルドと申請祭りだ!

UIScrollViewでズームを行ったときに常に対象を中央にする


難しいことを解決するには、手を付けやすいところから一歩ずつ。ということで、スクロールビューでズームを行ったときに、対象を常に中央に表示するサンプルコードを。

iOSでは、スクロール機能を提供するUIScrollViewがかなり便利。スクロールだけでなく、ズームも一緒に行う事ができる。ただ、UIScrollViewのズームは、そのまま使うと左上固定で拡大縮小されてしまう。これは違和感がある。画面の中心を基準に拡大縮小してほしいところ。

これをできるだけ簡単にやってみた。

ポイントは2つある。1つは、UIScrollViewのzooming viewとして、表示されているUIImageViewを使う。つまり、viewForZoomingInScrollView:の返り値として、UIImageViewのインスタンスを返す。これはまぁ、なんとなく分かるでしょ。で、気づかなかったのが、UIScrollViewはズーミングを行っているときは、zooming viewのサイズをcontentSizeとして使うらしい。つまり、zooming viewを使っている場合は、contentSizeを明示的に設定する必要は無い。つーか、設定したらまずいかも。

2つめは、UIImageViewを常に中央に表示するために、UIImageViewのframeのoriginを変更する。UIScrollViewのcontentOffsetじゃないよ。あくまでUIImageViewのframeを直接動かす。ただし、このときframeのsizeを変更しては行けない。sizeはUIScrollViewが変更してくれるので、それを使う。

ということで、それを実現してみたのが、次のコード。まずは初期化処理。UIScrollViewとUIImageViewを作成する。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Create window
    self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];

    // Create scroll view
    _scrollView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
    _scrollView.maximumZoomScale = 4.0f;
    _scrollView.delegate = self;
    [self.window addSubview:_scrollView];

    // Create image view
    _imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"test.png"]];
    [_scrollView addSubview:_imageView];

    // Update image view
    [self _updateImageViewSize];
    [self _updateImageViewOrigin];

    // Show window
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

    return YES;
}

UIScrollViewをインスタンス化して設定。UIImageViewをインスタンス化して設定。そして、UIImageViewのサイズと座標を設定する。それぞれ_updateImvewViewSizeと_updateImageOriginというメソッドを用意した。_updateImageViewSizeは、UIImageViewを縦幅いっぱいまたは横幅いっぱいまで広げるためのもの。_updateImageOriginは、それを画面中央に表示するために移動するためのものだ。

- (void)_updateImageViewSize
{
    // Get image size
    CGSize  imageSize;
    imageSize = _imageView.image.size;

    // Decide image view size
    CGRect  bounds;
    CGRect  rect;
    bounds = _scrollView.bounds;
    rect.origin = CGPointZero;
    if (imageSize.width / imageSize.height > CGRectGetWidth(bounds) / CGRectGetHeight(bounds)) {
        rect.size.width = CGRectGetWidth(bounds);
        rect.size.height = floor(imageSize.height / imageSize.width * CGRectGetWidth(rect));
    }
    else {
        rect.size.height = CGRectGetHeight(bounds);
        rect.size.width = imageSize.width / imageSize.height * CGRectGetHeight(rect);
    }

    // Set image view frame
    _imageView.frame = rect;
}

- (void)_updateImageViewOrigin
{
    // Get image view frame
    CGRect  rect;
    rect = _imageView.frame;

    // Get scroll view bounds
    CGRect  bounds;
    bounds = _scrollView.bounds;

    // Compare image size and bounds
    rect.origin = CGPointZero;
    if (CGRectGetWidth(rect) < CGRectGetWidth(bounds)) {
        rect.origin.x = floor((CGRectGetWidth(bounds) - CGRectGetWidth(rect)) * 0.5f);
    }
    if (CGRectGetHeight(rect) < CGRectGetHeight(bounds)) {
        rect.origin.y = floor((CGRectGetHeight(bounds) - CGRectGetHeight(rect)) * 0.5f);
    }

    // Set image view frame
    _imageView.frame = rect;
}

あとは、UIScrollViewDelegateメソッドを実装する。viewForZoomingInScrollView:でUIImageViewを返す。そして、スクロールビューがズームされるたびに呼び出されるscrollViewDidZoom:メソッドで、_updateImageViewOriginを呼び出す。これにより、常にUIImageViewが中央に表示される事が担保される。この呼び出しが、この手法の最大のポイントだね。

- (UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView
{
    return _imageView;
}

- (void)scrollViewDidZoom:(UIScrollView*)scrollView
{
    // Update image view origin
    [self _updateImageViewOrigin];
}

これでできるよん。

ここまでのソースコード:ScrollTest.zip

ビューの回転難しい


あー、もう、ビューの回転って難しいな!UIViewControllerを使ったビューの回転のプログラミングを書いているんだけど、これが何回やっても上手にできなくて。

単純に回転するだけならいい。最も単純な回転とは、回転するとそれにあわせて中のビューの大きさが外部のビューの大きさとピッタリ同じに変わってしまう場合。

これが、回転しても比率を保とうとすると、めんどくさくなってくる。縦と横とでスケールを変えなくてはいけない。さらに、縦と横とで表示する画面を変えると、さらにめんどくさくなってくる。たとえば、縦だと1ページ、横だと2ページの見開きにする、って場合ね。

これに、スクロールビューをからめて拡大縮小も可能にすると、もう何が何だか。zoomScaleを考慮しないといけないし、更新のタイミングも回転時だけではなくてズーム時になるし。

いっつも試行錯誤してしまう。充分に検討して、パターン化できるといいんだけど。

MOSA Software Meeting 2011参加受付開始


Mac時代から一貫してAppleプラットフォームでプログラミングする開発者を支え続けているMOSAが開催する年一回の開発者の祭典、MOSA Software Meeting 2011の参加者募集が始まっていた。

今年もまた、私は講師として参加させていただきます。お題は「iCloudの理論と実装」。iOS 5の目玉の新機能なんで、抑えておきたいよね。

参加申し込みは、MOSAのWebページの方からできますので、興味のある方は大橋会館でお会いしましょう。

[MandalArt-Dev] 定例ミーティング110927 – iOS 5対応


iMandalArt開発の現場を伝える、MandalArt-Dev。今回は、先日行われた定例ミーティングの様子を。

まず最初の議題はiOS 5対応。ほぼ対応は完了した、と言えるね。あとは、iOS 5 GMがリリースされれば、App Storeへの申請準備に入る。

これは全iMandalArtユーザにお伝えしたいんですけど、いまのiMandalArtおよびiMandalArt HDは、iOS 5で動作させた時に致命的な問題が確認されています。iOS 5の登場にあわせて新バージョンをリリースを予定していますので、バージョンアップの方をよろしくお願いします。

次は新機能の実装について。iOS 5対応を最優先にしていたので、こっちの方はあんまり進んでいない。次回までには進捗を出したいね。

新機能は、いままでの機能の漸近的な進化というよりは、新しいものを付け加えたという形に近い。となると、既存のアプリに追加する形がいいのか、それよりも新しいアプリという風に分けてしまった方がいいのか、で議論になる。結論はでないので、次回に持ち越し。

最後に、ミーティングの風景なども紹介しておきますね。