SimpleBoxes

WWDC 2012 雑感

Retina ディスプレイが搭載された新しい MacBook Pro が発表されました。

15 インチ、薄型で 13 インチ MacBook Pro より軽い、DVD ドライブはおろか HDD ドライブもなし。メモリもオンボード直付けで後からの換装は不可能。…… MacBook Air 15 インチのような存在というと語弊があるでしょうか。

Retina ディスプレイ MacBook Pro では、Tunderbolt を二口搭載しつつ、さらに HDMI を搭載しています。つまり外部ディスプレイ用ポートが標準で 3 つあることに。

とりあえず、現在の仕様上では、外部ディスプレイ二つまではサポートしているようです (つまり本体ディスプレイと合わせて 3 つのディスプレイ表示)。

折角、グラフィックチップも Intel HD Graphics 4000 と NVIDIA GeForce GT 650M の二つ搭載していますし、将来的にはソフトウェアアップデートで 3 つの外部ディスプレイサポートなんてこともあるんでしょうか……。

今回の WWDC の発表では、何といっても iOS6 が気になります。さっそくベータをダウンロードして使っていて、色んな変化があって嬉しいやら (今後の対応を考えると) 辛いやら……。

NDA があるので、どこまで触れていいのか分からないのが悩みどころ。Apple から公にされている部分は触れても構わないと思うので、そこを中心に……。

大幅に更新された Map アプリは、もうただ驚き。まだベータ版っぽい動作で粗はいっぱいありますが、使っていて楽しいアプリであることには間違いないです。……前職だったので、ちょっと指摘するのが辛いところもあるんですが、ナビ関係のアプリ開発はこれから大変そうです……。標準添付だもんなぁ、これ。

メールアプリ、Apple 公式の Pull-to-Refresh が来ましたね。この挙動、WWDC でデモしたのかな。それとメールや設定アプリのスクリーンショットで気付いた方もいるかもしれませんが、バッテリー状態などを表示するステータスバーのアピアランスが変わっています。グレーじゃなくなって、バッテリーアイコンが単色に……。結構雰囲気が変わって見えますね。

Facebook 対応は結構嬉しい。私が利用するかどうかというよりも、おそらく Twitter 同様 Apple からフレームワークとしてサポートされると思うので。そうなると、Facebook 対応アプリを作りたいという時に開発負担が激減すると思います。

初代 iPad が対応していないのはちょっと残念。それより前にリリースされている iPhone 3GS が対応しているので余計。メモリ的に厳しいのかなと予想。やはり Siri が……。

WWDC 基調講演で発表された以外にもいろいろアップデート (Mac Pro とか、AirPort Express とか) があったようで、盛りだくさんな感じですね。

スポンサーリンク

Objective-C / ARC で unsafe_unretained 利用時のインスタンス破棄タイミングについて

ここ最近のコーディングでは iOS5 SDK と同時に登場した ARC (Auto Reference Counting) を利用しています。

ARC の導入と注意点については、iOS 開発ブログ Natsu's note さんの一連の記事がとても参考になります。

C++ with boost に慣れた人なら、ARC はスマートポインタ (SmartPtr, AutoPtr) に近い動作をするという認識でよいと思います。

代入 (アサイン) 動作で参照カウンタが加算 (インクリメント) され、スコープを抜ける段階で release が呼ばるようなイメージで動作します。参照カウンタが 0 になった時点でオブジェクトが破棄されるのはこれまでの retain / release を使った従来の手法 MRC (Manual Retain-Release) と同様です。

明示的に retain / release を呼び出す必要がなくなり、巡回参照さえ気をつければ、メモリリークも軽減できる ARC はとても便利です。

そんな便利な ARC ですが、unsafe_unretained / weak 関連で不思議な動作をするのに気づいたので、忘れないようにメモしておきます。

Delegate 時の参照

[iOS5] ARC (Automatic Reference Counting) : Overview で触れられている通り、Cocoa プログラミングで多用される Delegate パターンでは「弱い参照 (weak reference)」を使って巡回参照によるメモリリークを防ぎます。

ただし、weak 修飾子は iOS5 以降でしか利用できません。iOS4 でも動作するアプリケーションにするためには、weak 修飾子を利用するところで unsafe_unretained 修飾子を使う必要があります。

unsafe_unretained 修飾子を使った場合、MRR で assign を利用したときと同様にアサインしたオブジェクトを適切なタイミングで nil 化してあげる必要があります。

しかしながら、unsafe_unretained 修飾子を利用する場合、ある条件下でオブジェクトが不用意に解放されてしまう場合があります。この場合、適切と思われる箇所で nil 化していても EXC_BAD_ACCESS の要因になりうるので注意が必要です。

多段 Delegate

さて、その「ある条件」について考察していきます。

以下は私が見つけたパターンですが、他にも同様なケースがあるかもしれません。

  1. ある Object A が Object B を作成し、その Delegate として動作します。

  2. Object B は内部で Object C を作成していて、その Delegate として動作していて、Object C からの通知を起点に Object B から Object A にメッセージが送信されます。

  3. Object A は Object B の Delegate メッセージを受け取り次第、Object B を利用しないので、Object B を破棄します。

文章にすると若干ややこしい感じがしますが、例えば、

ネットワーク越しのデータを処理するあるクラス (Object B) は内部で NSURLConnection (Object C) を利用していて、データ受信終了を起点に Object B でデータ処理を行い、Object A に通知する

というケースなどが該当します。

[図]多段 Delegate の基本パターンダイアグラム

コードで表現すると、

@class SampleClassA;
@class SampleClassB;
@class SampleClassC;

@protocol SampleDelegateB <NSObject>

- (void)callFromClassB:(SampleClassB *)object;

@end

@protocol SampleDelegateC <NSObject>

- (void)callFromClassC:(SampleClassC *)object;

@end

#pragma mark -

@interface SampleClassA : NSObject <SampleDelegateB>

@end

@interface SampleClassB : NSObject <SampleDelegateC>

@property (nonatomic, unsafe_unretained) id<SampleDelegateB> delegate;

@end

@interface SampleClassC : NSObject

@property (nonatomic, unsafe_unretained) id<SampleDelegateC> delegate;

@end

というような形で、SampleClassB では SampleDelegateC のデリゲートメソッド callFromClassC: 内で SampleDelegateB デリゲートメッセージを通知します。

- (void)callFromClassC:(SampleClassC *)object
{
  NSLog(@"  -> started  [%p] with '%@'",self,self.message);
  [self.delegate callFromClassB:self];
  NSLog(@"  -> endded   [%p] with '%@'",self,self.message);
}

つまるところ、オブジェクト C からのメッセージをフォワードするような感じのイメージ。

多段 Delegate のワナ

この形だけでは特になんてことはないのですが、

Object A は Object B の Delegate メッセージを受け取り次第、Object B を利用しないので、Object B を破棄します。

という条件が加わると、オブジェクトが破棄されるタイミングが実装によって変わってきます。

  • weak 参照を利用している

  • unsafe_unretained 参照を使っていて、プロパティ (メソッド) を通してデリゲートにアクセスしている

  • unsafe_unretained 参照を使っていて、メンバ変数でデリゲートにアクセスしている

オブジェクトが破棄されるタイミングが weak 参照をつかっているか、unsafe_unretained 参照を使っているか……さらにはプロパティを使っているかなどの条件で変わってきます。

サンプルコードを github に上げたので、それを元に挙動を確認することができます。

以下の実行結果は、Xcode 4.3 / iOS5 SDK を利用して行なったものです。

weak 参照を利用

SBSampleDelegate.h において

  • kUsingWeak 1
  • kAsseccingViaProperty 0
  • kUsingRetainAutoreleaseHack 0

のように設定した場合。

[A]===> initialized [0x6a67830]
[C]  -> initialized [0xXXXXXXX]
[B]  -> initialized [0xXXXXXXX] with 'msg0'
[C]  -> started     [0xXXXXXXX]
[B]  -> started     [0xXXXXXXX] with 'msg0'
[A]===> called      [0xXXXXXXX]
[A]===> removed     [0xXXXXXXX]
[B]  -> endded      [0xXXXXXXX] with 'msg0'
[C]  -> ended       [0xXXXXXXX]
[B]  -> destroyed   [0xXXXXXXX] with 'msg0'
[C]  -> destroyed   [0xXXXXXXX]

C → B と作成され、逆に B → C と破棄されています。期待通りの動作と言えそうです。

unsafe_unretained 参照を使っていて、プロパティ (メソッド) を通してデリゲートにアクセス

SBSampleDelegate.h において

  • kUsingWeak 0
  • kAsseccingViaProperty 1
  • kUsingRetainAutoreleaseHack 0

のように設定した場合。

[A]===> initialized [0xXXXXXXX]
[C]  -> initialized [0xXXXXXXX]
[B]  -> initialized [0xXXXXXXX] with 'msg0'
[C]  -> started     [0xXXXXXXX]
[B]  -> started     [0xXXXXXXX] with 'msg0'
[A]===> called      [0xXXXXXXX]
[A]===> removed     [0xXXXXXXX]
[B]  -> endded      [0xXXXXXXX] with 'msg0'
[B]  -> destroyed   [0xXXXXXXX] with 'msg0'
[C]  -> ended       [0xXXXXXXX]
[C]  -> destroyed   [0xXXXXXXX]

C → B と作成され、逆に B → C と破棄されていますが、分かるでしょうか、[B] -> destroyed[C] -> ended の呼び出される順番が逆になっています。

SampleClassC からデリゲート B を呼び出しているメソッド callDelegate のスコープにまだいる最中に SampleClassC のデリゲートである SampleClassB のインスタンスが破棄されています。

これですぐに問題になるケースはぱっと思いつきませんが、ちょっとだけ不安な感じ。

unsafe_unretained 参照を使っていて、メンバ変数でデリゲートにアクセス

SBSampleDelegate.h において

  • kUsingWeak 0
  • kAsseccingViaProperty 0
  • kUsingRetainAutoreleaseHack 0

のように設定した場合。

[A]===> initialized [0xXXXXXXX]
[C]  -> initialized [0xXXXXXXX]
[B]  -> initialized [0xXXXXXXX] with 'msg0'
[C]  -> started     [0xXXXXXXX]
[B]  -> started     [0xXXXXXXX] with 'msg0'
[A]===> called      [0xXXXXXXX]
[A]===> removed     [0xXXXXXXX]
[B]  -> destroyed   [0xXXXXXXX] with 'msg0'
[B]  -> endded      [0xXXXXXXX] with '(null)'
[C]  -> ended       [0xXXXXXXX]
[C]  -> destroyed   [0xXXXXXXX]

明らかにおかしい挙動になります。

まだ C からのデリゲート callFromClassC: のスコープにいるのにも関わらず、dealloc が呼び出されています。

SampleClassB のインスタンスが破棄された後、callFromClassC: のメンバである mMessage にアクセスしているので、(null) と表示されています。場合によっては EXC_BAD_ACCESS の要因になります。

retain-autorelease ハック

という訳で unsafe_unretained 参照を利用すると、weak 参照とは異なった挙動になってしまいます。

これは MRR で assign を利用した場合でも起こりうる現象です。MRR ではこれに対して、

[[obj retain] autorelease]

retain と autorelease を併用することで、当該オブジェクトを autorelease プールに登録して、少なくともスコープ内はオブジェクトが破棄されないようにすることができました。

ご承知の通り、ARC では retain / autorelease メソッドの呼び出し自体が禁止されているので、同じハックは利用できません。

ただ、ローカルな変数に対しては、__autorelesing 修飾子を利用することによって autorelease プールを利用することを明示できます。

__autorelasing id temp = obj;

これでスコープ内では temp を利用すると、インスタンス obj に対して retain-autorelease で呼び出したのと同じような効果が得られます。

SBSampleDelegate.h において

  • kUsingWeak 0
  • kAsseccingViaProperty 0
  • kUsingRetainAutoreleaseHack 1

のように設定した場合、SampleClassA において retain-autorelease ハックを利用します。

[A]===> initialized [0xXXXXXXX]
[C]  -> initialized [0xXXXXXXX]
[B]  -> initialized [0xXXXXXXX] with 'msg0'
[C]  -> started     [0xXXXXXXX]
[B]  -> started     [0xXXXXXXX] with 'msg0'
[A]===> called      [0xXXXXXXX]
[A]===> removed     [0xXXXXXXX]
[B]  -> endded      [0xXXXXXXX] with 'msg0'
[C]  -> ended       [0xXXXXXXX]
[B]  -> destroyed   [0xXXXXXXX] with 'msg0'
[C]  -> destroyed   [0xXXXXXXX]

weak 参照と同様に C → B と作成され、逆に B → C と破棄されています。

ログでは同じように見えていますが、こちらの実装では、B は autorelease プールのタイミングで破棄されているので、内部的には異なる挙動になっています。ただ、不用意な破棄がなくなり、アクセスバイオレーションはなくなります。

スポンサーリンク

SBPullToRefreshHeaderView - 「引っ張って更新」を再実装してみる

HMDT さんから開発者向け電子書籍がリリースされています ([本] HMDT JOURNAL 創刊 | Cocoaの日々情報局 経由)。

早速、Vol.001 と Vol.002 を購入してみました。木下さんらしい読みやすい文体で、かなり丁寧に書かれています。

……特定の連載記事だけをバラで購入できたら嬉しいなぁ……なんて。ともあれ、今後の展開が楽しみです。

EGOTableViewPullRefresh

さて、この HMDT JOURNAL Vol.001 で紹介されている EGOTableViewPullRefresh は、いわゆる「引っ張って更新」を実現するクラスで、Facebook 謹製のライブラリでも採用されていたりする有名なライブラリです。

組み込みも簡単で、コードも分かりやすく記述されているライブラリなのですが、導入にあたってコントローラ側で UIScrollViewDelegate のメッセージをフォワードする必要がある点がちょっと不満。

例えば、UIButton ではボタンのハイライトのためにタッチイベントをコントローラ側からフォワードしなくても、ボタン側で勝手に処理してくれるように、EGOTableViewPullRefresh もスクロールイベントを勝手に処理してくれたらなぁと思うわけです。

SBPullToRefreshHeaderView - yet another "pull-to-refresh"

……そこで自分で「引っ張って更新」するクラス SBPullToRefreshHeaderView を自作してみました。

[図] SBPullToRefreshHeaderView の実装例

ARC 対応で __weak 修飾子を使っているので、iOS5 以降でお使いいただけます。

他に EGOTableViewPullRefresh から微妙に変わっている部分に「離して更新」の時にリロード用画像を使っています。OS X 向け Twitter アプリケーションのような感じ。

サンプルデモのコードにある通り、コントローラ側では SBPullToRefreshHeaderView の初期化メソッドにターゲットとなるスクロールビューを渡すと、あとは SBPullToRefreshHeaderView 側でよしなにしてくれます……はずです。

mRefreshHeaderView = [[SBPullToRefreshHeaderView alloc] initOnScrollView:self.tableView
                                                            withDelegate:self];

デリゲート SBPullToRefreshHeaderViewDelegate のメソッドはふたつ。

@protocol SBPullToRefreshHeaderViewDelegate <NSObject>

/// 「引っ張り更新」の発動 (ユーザが更新するためにスクロールビューを離した) を通知します。
/// @param headerView - 関連する SBPullToRefreshHeaderView のインスタンス
- (void)didTriggerRefresh:(SBPullToRefreshHeaderView *)headerView;

/// ターゲットが「ローディング」状態がどうかを確認します。
/// @param headerView - 関連する SBPullToRefreshHeaderView のインスタンス
/// @return ローディング状態にある場合、YES をそうでない場合 NO を返します
- (BOOL)isRefreshStillProcessing:(SBPullToRefreshHeaderView *)headerView;

@end

コントローラ側では基本的にはこのふたつのデリゲートメソッドを実装して、ローディングが終了した後に「resetView:」メソッドを送信します。

SBPullToRefreshHeaderView の実装

SBPullToRefreshHeaderView ではスクロールイベントを処理するために KVO (Key-Value Observing) を使っています。

スクロールが発生すると、UIScrollViewcontentOffset が変化することに着目して、そこでスクロール時に処理する内容を記述しています。

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
  if (object == mScrollView &&
      [keyPath isEqual:@"contentOffset"])
  {
    [self scrollViewDidScroll:mScrollView];
    if (mIsDragging != mScrollView.isDragging)
    {
      if (!mScrollView.isDragging)
      {
        [self stopDragging];
      }
      mIsDragging = mScrollView.isDragging;
    }
  }
}

ユーザーがターゲットのスクロールビューから指を離したかどうかの判定もここで行っています。スクロールの変化で判定しているので、実際のタッチリリースとは異なるタイミングになりますが、動作させてみた感じ特に違和はない感じ。

オブザーブを開始・終了するタイミングが少しハック的な実装になっています。

……というのもオブザーブを開始した時点で参照カウンタがインクリメントされてしまうため、どこか適当なタイミングでオブザーブを終了してあげないといつまで経ってもオブジェクトが解放されなくなってしまいます。

SBPullToRefreshHeaderView の実装では、ターゲットとなっているスクロールビューの子ビューとして追加されたときにオブザーブを開始、親ビューがターゲットから外れた時点でオブザーブを終了するようにします。

- (void)didMoveToSuperview
{
  if (self.superview == mScrollView)
  { // The view has been added into the target scroll view so it starts 
    // observing contentOffset changes.
    [mScrollView addObserver:self 
                  forKeyPath:@"contentOffset" 
                     options:NSKeyValueObservingOptionNew 
                     context:nil];
  }
  else
  { // The view has been removed from the target scroll view so it stops 
    // observing contentOffset changes.
    [mScrollView removeObserver:self
                     forKeyPath:@"contentOffset"];
  }
}

UIView の 「didMoveToSuperview」メソッドで親ビューの変化をキャッチできるので、そこでオブザーブの開始・終了を制御しています。

GitHub にサンプルデモと一緒に置いてみましたので、もしよろしければお使いください (MIT-License)。

スポンサーリンク

Xcode 4.3 リリース

二月になってしまいましたが、2012 年もよろしくお願いします。

Xcode 4.3 がリリースされました。

Mac App Store との親和性を高めるため、Xcode 4.3 からはインストール先が変更されています。

  • Xcode 4.2 まで : /Developer
  • Xcode 4.3 から : /Applications

インストール方法も変わりました。Xcode 4.2 までは何らかの方法で Xcode のインストーラを起動する必要がありました。

Xcode 4.2 では Mac App Store からダウンロードされるものは「Xcode Install」で Xcode そのものではありませんでした。

Xcode 4.3 からはインストーラは目に見えては存在しません。App Store からダウンロードして、そのまま他のアプリケーションと同じように起動するだけです。

Xcode 4.3 はインストールされる場所が最大の違いで、機能的な違いはほとんどない印象です。

Xcode に付録されるユーティリティ

Xcode 4.2 まで /Developer/Applications の中にあった Instruments や Icon Composer, FileMerge といったユーティリティは Xcode 4.3 から Xcode アプリケーション内に内包されています。

Dashcode, Quatz Compozer などこれまで Xcode に付録 (?) として付いてきたいくつかのアプリケーションは Xcode 4.3 には含まれていません。

developer.apple.comダウンロードセンターから別途ダウンロードする必要があります。

  • Dashcode → Dashcode for Xcode - February 2012
  • Quartz Composer → Graphics Tools for Xcode - February 2012

Instruments など Xcode 4.3 に内包されているアプリケーションを起動するには Xcode を立ち上げて、Xcode メニューより「Open Developer Tool」を利用します。

[図] デベロッパツールメニュー。

Xcode に内包されているアプリケーションでも起動させた状態で Dock に保持するようにすれば、Dock から (Xcode を通さずに) 立ち上げることができます。Xcode に内包されているアプリケーションは Spotlight では拾ってくれないようです。

コマンドラインツール

Xcode 4.3 にはもちろんコンパイラは付いてきますが、Xcode 4.2 まで /Developer/usr/bin に含まれていたいくつかのツールは含まれていません。前述のダウンロードセンターからダウンロードするか、設定画面の「Downloads」より「Command Line Tools」をダウンロードします。

[図] Xcode 4.3 設定内のダウンロード。

Xcode 4.3 からの仕様変更により OS X のパッケージマネージャ Homebrew は Developer Preview の時には動作しなくなってしまいましたが、Command Line Tools をちゃんと入れれば、大丈夫な様子。

以前の Xcode との共存

Xcode 4.3 はこれまでの Xcode と同様、以前のバージョンの Xcode と共存が可能です。一番最初に Xcode 4.3 を立ち上げたときにインストールされている Xcode をゴミ箱に移動するかどうか聞かれます。

[図] Xcode 4.3 最初の起動時に表示されるダイアログ。

該当するディレクトリを単にゴミ箱に移すだけのようで、/Developer/Library/uninstall-developer-folder は実行されない様子。

ヘルプでは「(古い Xcode は) 後からでもいつでもゴミ箱に入れられます」とあって、uninstall-developer-folder の実行には触れられていません。ゴミ箱に移して削除すればアンインストールされるんでしょうか。

スポンサーリンク

転職しました

先日、私がニュージーランドに移住して初めて就職し、八年間勤めた会社 (ポータブルナビゲーションデバイス、いわゆる「カーナビ」のソフトウェア開発) を退職しました。

[写真]退職の際にもらったカード。皆からの寄せ書きです。

退職時のメールは以下の通り。

Dear All,

It's my last working day here at <company name>.
I would like to thank you all for your great support.

I have been working here over 8 years; it's long long and really exciting journey.
I will miss all such comfortable environment - great people, great products, and walking distance from home.

Please keep in touch.

I can be reached :

via email : <email address>
on LinkedIn : <LinkedIn url>
on Facebook : <Facebook url>
on Skype : <Skype account>
via mobile : <mobile phone number>

I wish you all the best for the future.

Best regards,
Takuya

およそ九年前にもニュージーランド移住にあたって、日本で五年間勤めた某大手電機メーカーを辞めました。その時と比べると私の中で感じる「重み」が違います。

九年前、日本で退職したときはニュージーランド移住がまず念頭にあり、ほぼ何もない状態からスタートする、いわば「リセット」的な意味合いが多分にありました。

不安も一杯でしたが、失うものもないという意識もあって「すっきり」「心機一転」という気持ちが強かったと思います。世間知らずであまり後先考えていなかったというのもあったと思います。

世間知らずなのは、今も大して変わっていない気もしますが。

八年前、ソフトウェアエンジニアとして就職。

シニアソフトウェアエンジニアとしてテクニカルリーダーなどを経験し、最終的にはソフトウェアチームリーダーとして、ソフトウェア開発ばかりでなくマネージメントも含め、たくさんの貴重な経験を積むことができました。

会社自体も、山あり谷あり。

飛ぶ鳥を落とす勢いの時……新社屋落成セレモニーに時の首相が訪問しました……もあれば、大規模なリストラが敢行されたこと……人数削減のため同ポジションの人の間で点数をつけて上位数名だけ残る……もありました。

そのような過程を経た八年間。

職場はとても快適で、上司・部下に限らず皆からの信頼も感じていて、自信もつきました。……正直なところ「去りがたい」「怖い」という気持ちも少なからずあります。

一方で、あまりにひとつの会社に依存しすぎるのもリスクとも思っていたのも確かです。

ポータブルナビゲーションデバイスのソフトウェア開発がどこまで「保つ」ものなのかという面の不安もあります。

八年間の経験を通して、技術面でもコミュニュケーション面でも英語圏で十分に通用するという自信はつきましたが、一社でのみの経験で、それが他所でも通用する保証はありません。

色んなオプションを検討した末、今回転職に踏み切りました。

不安がないと言えば嘘になりますが、全く異なる分野でのソフトウェア開発ということで新鮮な気分もあります。

自分のスキルを生かすという点ではこれまでと変わりありません。とりあえず、頑張ってみようと思います。

スポンサーリンク

ハーフマラソンに挑戦してみた

先日行われたオークランドマラソンにて、ハーフマラソン完走しました→結果は 1 時間 42 分

目標としていたタイムは 1 時間 45 分で、それを上回ることができました。初ハーフマラソンとしては上出来だと自画自賛。

  1. きっかけ
  2. 年始目標
  3. トレーニング
  4. オークランドマラソン

きっかけ

もともと身体が小さくて筋力がない方なのですが、それに加え 30 歳過ぎまで喫煙をしていたせいもあり、全体的な持久力の低下も少し心配していました。

それで、二年前の誕生日頃から、体力づくりというか体力維持を目的としてジョギングを始めました。

仕事が終わってから夕食の前に自宅の周辺 3km ほどのコースを走ります。

理想的には毎日走りたいところですが、仕事や天気の状況次第で週に二、三日ぐらい走れるという感じのペース。

とにかく続けることが目標という感じで始めたのですが、ある程度の強制力がないと続かないという嫁さんの進言で、ビーチシリーズという地元のローカルレースにも参加しはじめました。

ビーチシリーズは 11 月から翌年 3 月にかけて毎週火曜日、地元のビーチで行われるローカルレースです。ランの他にもスイムやパドルボードなどの種目があります。

ビーチシリーズのランは 5km。文字通り浜辺を走ります。潮の満ち引きの加減でコースの状態や長さが安定していないのが難点ですが、レースという形式で走るのが刺激になります。

参加し始めた当初は 5km で 25 分程度だったのですが、段々と慣れてきたせいか、昨年度は 21 分程度まで縮めることができました。

年始目標

とりあえず 5km 程度ならばそこそこ走れる、という自信がついてきたので、もう少し長い距離に挑戦してみようと思いたったのが、今年の始め。

長距離ランの代表格はなんと言っても「マラソン」になると思いますが、いきなりマラソンはキツいかもと思い、「今年中にハーフマラソンを完走する」という目標を立てました。

最初は地元で行われる North Shore Marathon に参加しようかなと思っていたのですが、たまたま会社の同僚に話したところ、「おぉ、そいつはグッドアイデアだ。俺も参加しよう」ということになりました。

折角なら一番大きな大会にしようということでオークランドマラソンに参加することに……。

オークランドマラソンの方が開催時期が二ヶ月遅く、その分、準備期間を取れるという要因もありました。

もちろん完走が目標で、できれば二時間を切るタイムで完走したいというのが、とりあえず参加を決めた当初の目標。

トレーニング

会社の同僚も巻き込んで、いよいよ後に引けなくなりました。

五月頃から普段 (3km) よりも長めの距離を走れるように意識し始めます。

ざっくりトレーニングの方法を調べてみましたが、単純に長い距離走ればよいというものではないみたいで、短距離ダッシュなども取り入れる必要がある感じです。

そこで実際、短距離ダッシュもやってみたのですが、そうするといかにも「練習」っぽくなってしまい、長続きしそうにありません。

あくまでも長く続けることが第一なので、トレーニング方法を参考にしつつ、自分なりに以下のように決めました。

平日
短い距離 (3km) を早めのペース (1km 4 分 30 秒を切るペース)。
休日
長い距離 (10km 以上) をゆっくりペース。余裕があれば、さらに中距離 (5km 〜 8km) を別の日に走る。

平日は 30 分未満、休日は 1 時間以上走るという感じです。

これまで 10km を超える長距離は走ったことがありませんでしたが、ここ二年間走っていたおかげで 1km 5 分ペースであれば、結構走れる感触。

ただ、実際走ってみると……

  • 最初の 4km が少しキツい。おそらくウォームアップ不足。
  • 10km 過ぎたあたりから膝に負担を感じるようになる。
  • 15km 過ぎたあたりから股関節に負担を感じるようになる。

心肺よりもむしろ関節への負担が想像以上にありました。スクワットやストレッチなどを都度きちんとやるようにして、膝や股関節への負担に備えます。

ストレッチなどは走る前にはもちろんですが、家でぼーっとしているときやプリンを作っている合間などスキマ時間も利用します……といえ、無理にしているわけではなく、気づいたら都度ストレッチなどをするという感じ。とにかく練習っぽくせずに「日常の延長」でできれば、という感覚で。

同僚に誘われて、dailymile というオンラインサービスにも登録してみました。走った記録は手元にも残していましたが、dailymile ではペース計算や週毎・月毎の集計などを自動でやってくれますし、 facebook との連携もあったりして、便利なツールです。

オークランドマラソン

九月・十月のトレーニングの内容から、1km 5 分のペースを基本にして、21km x 5 分 = 105 分 = 1 時間 45 分を最終的な目標タイムにします。

オークランドマラソンは交通機関への影響を配慮してか、早朝にスタートするのが特徴です。

[写真]スタート周辺の様子

日が上がる前からスタート地点である「デボンポート」に集合します。早朝なので、公共の交通機関はなくて、臨時フェリーと臨時バスが出ます。

最寄りのバス停まで 4km 弱もの距離があるのがちょっとやっかいでしたけど、結果的にはちょうどよいウォーミングアップになりました。

[写真]日の出をスタート地点から望む

フルマラソンとハーフマラソンは同じ地点からスタートします。フルマラソンが先にスタートして、その後ハーフがスタート。フルマラソンのスタート後、ハーフのスタートを待っている間に日の出を迎えました。

[写真]スタートゲート

スタートゲート。「Elite」のカンバンが見えるでしょうか。速い人はゲート前に並んで遅い人はゲートから離れた位置でスタートします。人が並び始める前にちょっと様子見。

[写真]ノースコートにて

スタート地点からおよそ 10km あたりで嫁さんと娘が応援してくれました。自作の横断幕を持つ娘と走り過ぎる私 (後ろ姿)。まだこの頃は余裕が……。

[写真]ハーバーブリッジを登る

スタート地点からおよそ 15km あたり、オークランドマラソンの (フルマラソンなら前半の) クライマックスとも言える「ハーバーブリッジ」に差し掛かります。

ここは上り始め。ここからおよそ 1km 弱ほどそこそこキツい上り坂……。

[写真]頂上 (?) が見えてくる

はためくニュージーランドの国旗。ちょっと旗の真下がブリッジの頂上にあたります。

[写真]ハーバーブリッジからシティを望む

ハーバーブリッジは通常、車でしか通行できず、また基本的に停まることができません。車から降りて渡る機会などそうそうないので、ハーバーブリッジを渡っているときには写真は撮ってやろうと思ってました。

ハーバーブリッジでの写真は走りながら撮っています。幸い十分明るかったので、思ったよりブレもなく撮れました。

[写真]ゴール地点

続々とゴール。ゴール地点には給水だけでなく、バナナの配布もしてました。風船をつけた人はペースメーカー。

[写真]ラストスパート

私もなんとかゴール。

オークランドマラソンはフルマラソン前半部分 (つまり、ハーフマラソン全コース) のコースの起伏が激しいのが特徴で、ハーバーブリッジがそのクライマックスになるんですが、それが終わった後がキツかったです。起伏での消耗が起伏が終わった途端にどっと来る感じ。

ハーフを無事に完走し、次はフル?とも聞かれたんですが、フルマラソンを走るにはもう少しトレーニングが必要かも。

ちなみにその日の午後は爆睡。どうにか次の日、会社には出勤することができましたが……。

スポンサーリンク

Re: Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編)

JunichiIto さんによる「Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編)」という記事を見かけて自分でもやってみる。

正確に時間を測ったわけではありませんが、問題 1 と問題 2 あわせて一応 90 分で解けたと思います。

問題1: Excel列名変換問題
  • 仕様
    • 入力されたアルファベットを数字に変換する。
    • 変換ルールはExcelの列名と同等。
    • 例) A=1、B=2、Z=26、AA=27、XFD=16384
  • 起動時引数
    • [0] アルファベット (A〜ZZZZ...[上限なし])
  • 実行例
    • ExcelColConv.pl A → 1
    • ExcelColConv.pl AA → 27

[→Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編)]

問題 1 に対する私の回答

問題2: Excel列名変換問題(逆変換)
  • 仕様
    • 入力された数字をアルファベットに変換する。
    • ただし、問題1で作ったプログラムを拡張すること。
  • 起動時引数
    • [0] 0=数字へ変換、1=アルファベットへ変換
    • [1] 変換する数字またはアルファベット(どちらも上限なし)

[→Excel列名変換問題で第2回社内プログラミングコンテストを開催してみた(前編)]

問題 2 に対する私の回答

問題 1 回答

#!/bin/perl

if ($ARGV[0] =~ /[A-Za-z]+/)
{
  print &convert(uc($ARGV[0])) . "\n";
}
else
{
  &usage();
}
exit 0;

sub usage
{
  print 'Usage: ',$0,' input',"\n";
}

sub convert
{
  my $input  = shift;
  my $output = 0;

  my $rank = 0;
  foreach my $char ( reverse(split(//,$input)) )
  {
    my $num = index('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $char) + 1;
    $output += $num * (26 ** $rank++);
  }

  return $output;
}

アプローチとしては、3 位の方と同等ですね。一応、入力パラメータチェックしてます。

問題 2 回答

#!/bin/perl

if ($ARGV[0] eq '0' and $ARGV[1] =~ /[A-Za-z]+/)
{
  print &convert(uc($ARGV[1])) . "\n";
}
elsif ($ARGV[0] eq '1' and $ARGV[1] =~ /[0-9]+/ and $ARGV[1] > 0)
{
  print &rev_convert($ARGV[1]) . "\n";
}
else
{
  &usage();
}
exit 0;

sub usage
{
  print 'Usage: ',$0,' dir input',"\n";
  print '       dir 0 : alpha to num [input must be alphabet]'."\n";
  print '       dir 1 : num to alpha [input must be number greater than 0]'."\n";
}

sub convert
{
  my $input  = shift;
  my $output = 0;

  my $rank = 0;
  foreach my $char ( reverse(split(//,$input)) )
  {
    my $num = index('ABCDEFGHIJKLMNOPQRSTUVWXYZ', $char) + 1;
    $output += $num * (26 ** $rank++);
  }

  return $output;
}

sub rev_convert
{
  my $input  = shift;
  my $output = '';
  my @chars = split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
  my $base = @chars;

  my @stack = ();
  while ($input > $base)
  {
    my $num = $input % $base;
    push(@stack, $chars[$num - 1]);
    $input = int($input / $base);
    # Needs to decrement $input if $input value is in multiple of $base
    if ($num == 0)
    {
      $input--;
    }
  }
  # Now handles within $base case
  push(@stack, $chars[$input % $base - 1]);

  return join('',reverse(@stack));
}

入力数値が基数にあたる 26 の倍数の時、桁を正しく処理する必要があるのがトリッキーな部分になるでしょうか。

一応、ざっくり確認したつもりですが、間違っていたらごめんなさい。

[2010.11.04 03:30 追記] perl の場合、配列に対して負のインデックスを指定すると、配列の後ろからアクセスするという仕様があります。なので、$input % $base の結果が 0 になる場合、@stack には "Z" が格納されます。

スポンサーリンク

十歳になった娘へ

十歳の誕生日、おめでとう!

先日、あなたは十歳の誕生日(たんじょうび)(むか)えました。

十歳。

あなたの眼には世界はどのように映っているでしょうか。

私が十歳、つまり小学四年生だった(ころ)、とても(なか)の良い友だちがいて、毎日のように一緒(いっしょ)にマンガを描いていました。

右のカービィの亜種(あしゅ)みたいなキャラクターは、その頃描いていたマンガのメインキャラクターの一人。フェルトで作ったものですが、今でも手元にあるのがびっくり。

マンガもそうだけど、自分でストーリーを考えるのが好きだったので、星新一のショートショートなんかを真似(まね)た短編小説 (ショートストーリー) みたいなものを書いたりもしていました。

マンガも小説もあまりに(つたな)く、とても見せられるようなものではなかったけれど、漠然(ばくぜん)と「漫画家(まんがか)」か「小説家(しょうせつか)」になりたいと思っていました。

その夢がガラリと変わったのは、誕生日に買ってもらった任天堂(にんてんどう)のファミリーコンピュータ、いわゆる「ファミコン」のせい。

ファミコンを始めとするビデオゲームには、それこそ朝から(ばん)までずっとゲームをしていたと言っても言い()ぎでないくらい、のめり()みました。

最近はほとんどプレイすることもなくなってしまったけれど、ニュージーランドに来る直前(ちょくぜん)あたりまで、ビデオゲームばかりやっていたぐらいです。ウソだと思うならあなたのお母さんに聞いてごらんなさい。

ゲームを上手(じょうず)にプレイできれば(うれ)しいけれど、残念(ざんねん)ながら「ゲームをうまくプレイする」才能にはあまり(めぐ)まれませんでした。その分、ゲームを創造(そうぞう)する方に興味(きょうみ)が向いてました。……「ゲームデザイナー」になりたいと思うようになります。

それが実現(じつげん)するかはどうかはともかく、私が十歳に(えが)いていた「漫画家」「小説家」「ゲームデザイナー」という夢は、私に大きく影響(えいきょう)しました。その頃に描いた夢が(ちが)ったものであれば、私は確実(かくじつ)に違った人生を歩んでいたであろうと思います。

私が十歳の頃、「ニュージーランド」という十歳の頃には知りもしなかった場所で生活しているとは夢にも思いませんでした。

夢に思っていること・夢にも思わなかったこと、これからあなたの将来(しょうらい)に起こるであろうことは(だれ)にも分かりませんが、あなたの目の前には果てしない可能性が広がっていることだけは確かです。

あなたの人生が素晴(すば)らしいものであると胸をはって言えるよう、私も (そして、あなたのお母さんも) 精一杯(せいいっぱい)のサポートをしていこうと思っています。

スポンサーリンク

ルンバがうちにやってきた

新製品が先日発表されたばかり Roomba (ルンバ) ですが、うちに現行モデル (530) がやってきました。

[写真]Roomba 530 パッケージ

購入したのは、530 というスタンダードモデル。ベースに自動的に戻る機能があります。

[写真]Roomba 530 開封の儀

パッケージには

  • Roomba 本体
  • 替えフィルタ
  • ベースステーション
  • AC アダプタ
  • バーチャルウォール
  • ブラシクリーニング用ツール (赤いやつ)
  • 取扱い説明書

が同梱されていました。日本で売っているモデルとは同梱品の内容などが異なる感じです。

[写真]Roomba 530 内容物

AC アダプタは Roomba 本体に繋いで充電することもできますが、通常はベースステーションに繋いでおき、ベースステーションから充電するという形になります。

早速利用してみましたが、評判通りすこぶる便利。

猫が家族の一員になってから、フロアが埃っぽくなりがちでしたが、隅々まで (ソファーの下も入り込んで) 綺麗にしてくれます。

障害物にぶつかった際、赤外線センサーで周囲の状況を確認しながら、回転して次のルートを決定する様子。デジタルカメラで撮影すると、赤外線センサーが某モビルスーツのモノアイのごとく光る様子が確認できます。動画では音をなくしてしまいましたが、それなりに大きな音がします。

うちはほぼ全面的にフローリング (板の間) で、マットなども敷いていません。埃っぽいとザラザラした感触がありますが、Roomba が掃除した後だと、そうしたザラザラ感が明らかになくなります。人がざっと掃除機をかけるよりはるかに丁寧に掃除してくれる印象です。

Roomba を導入した人のレポートを見ると「Roomba のおかげで床にモノを置かないようになる」と記述が見受けられましたが、うちでも同様に Roomba 導入以降、心なしかうちの中がすっきりしたような気がします。

スポンサーリンク

Presario CQ57 と Windows 7

PC 代替えの年

今年は自宅で使っている PC の厄年 (?) なのか、使っていた三台を立て続けに代替えしました。

[写真]PC 勢揃い。左から Presario CQ57、ThinkPad Edge 14、MacBook Pro、MacBook

実のところ、MacBook Pro は最後に代替えしたマシンになります。

  • Thinkpad R52 → ThinkPad Edge 14 [嫁さん用]
  • Thinkpad T43 → Presario CQ57 [娘用]
  • MacBook → MacBook Pro 13 [私用]

学校で課題が出たりするので、娘用にも PC を用意しています。

会社から型落ちマシン (Thinkpad T43) を購入して、それを娘用に使っていたのですが、今年になって絶不調。起動してもマウスカーソルを動かした途端にフリーズする謎の現象に見舞われます。

リカバリユーティリティを使って OS の再インストール、内蔵ハードディスクドライブの換装、メモリの挿し直しなど試せることは大概やってみましたが、それでも症状は改善されず、やむなく新規機種の購入を検討することに……。

  • 場所を選ばずに利用できる利点がやはり大きいので、ラップトップが前提。
  • できるだけコストを抑えたい。
  • コスト面では、ネットブックが有利だけど、
    • DVD/CD を利用する機会が多い娘の利用用途では、DVD ドライブ非搭載な機種は向いていない
    • 娘は視力が若干弱いので、できるだけ大きな画面がよい
    という点で、ネットブックは候補から外れる。
  • たまたま会社からもらった商品券が手元にあって、それが利用できるお店。

という諸々の条件を加味した結果、Compaq Presario CQ57-104TU というマシンを購入することに。

販売価格で 4 万円弱でしたが、商品券を使ったので、実費で 1 万円も払わずに購入しました。その後若干値上がりしたりもしたので、結果的には底値のタイミングで購入できました (これからまた下がるかもしれませんが……)。

HP との統合で、コンパックのプレサリオというブランドは、日本では新規では扱っていないようですが、ニュージーランドではエントリー向けブランドとして認知されているせいか、まだ扱われている様子。

スペック比較

先にも述べたとおり、日本では扱っていない機種なので、参考になるかどうか怪しいですが、スペックを大まかに比較すると以下の通り。

機種 MacBook Pro 13 ThinkPad Edge 14 Presario CQ57
CPU / 動作周波数 Intel Core i5 2.3GHz Intel Core i3 2.13GHz Intel Celeron T3500 2.1GHz
システムバス周波数 1333MHz 1066MHz 800MHz
搭載メモリ 8GB DDR3 SDRAM
PC3-10600
3GB DDR3 SDRAM
PC3-8500
2GB DDR3 SDRAM
PC3-8500
グラフィックス Intel HD Graphic 3000 Intel HD GMA Intel GMA4500MHD
ディスプレイ 13 インチ 光沢
1280 x 800
14 インチ 非光沢
1366 x 768
15 インチ 光沢
1366 x 768
内蔵 HDD 320GB 7200rpm SATA 250GB 5400rpm SATA 320GB 5400rpm SATA
重さ 2.04kg 2.25kg 2.5kg
大きさ 32.5cm x 22.7cm x 2.41cm 34.4cm x 23.3cm x 3.70cm 37.6cm x 24.7cm x 3.58cm
バッテリー 63.5Wh (公称 7 時間) 57Wh (公称 4.5 時間) 47Wh
入出力 I/F USB2.0 x 2
SD カードスロット
Thuderbolt
Firewire 800
USB2.0 x 3
SD カードスロット (7 in 1)
VGA
HDMI
USB2.0 x 3
SD カードスロット
VGA
新品販売価格
(当時@NZ)
約 13 万円 5 万円後半 3 万円後半

[写真]開けた状態で並べてみました。図らずも全てラッチレス構造のマシンになりました。

使い心地

Presario CQ57 は、格安エントリーモデルという位置づけになります。

プラスティック (ポリカーボネート?) の外装はシンプルで、ゴテゴテしがちな底面も思っていた以上にすっきりしていました。

ThinkPad Edge 14 / MacBook Pro 13 と同様、Presario CQ57 もラッチレスな構造になっています。

Presario CQ57 は大きさの割に軽く、モニターを閉じる強さがそれに比べて強いので、モニターを片手で開こうとすると、それにつられて本体側も持ち上がってしまうことがままあります。

[写真]CQ57 のモニターを開ける。モニターだけを持って開こうとすると、本体側も持ち上がってしまう。

余談になりますが、ThinkPad Edge 14 は ThinkPad では珍しい (?) ラッチレス構造ですが、モニターがぴったりと閉じてくれない (閉じた時に若干隙間ができる) のが少々不安……。

キーボードは、Enter や Backspace キーの右側に、さらに一列 Home や End などのキーが並んでいるタイプのもので、ちょっと苦手。

トラックパッドは段差のないユニークなもので、マルチタッチにも対応しています。ボタン部分は「パコパコ」という打鍵感がチープな感じなのは否めません。使い勝手は決して悪い方ではないと思うのですが、MacBook Pro のそれと比較するとやはり劣ります。

[写真]CQ57 のキーボードとトラックパッド。トラックパッド部は段差がなく、埃などが溜まらない構造。

現状で利用頻度の高い順から

  1. ウェブサイト閲覧 (含 Flash)
  2. オンライン動画鑑賞
  3. DVD 動画鑑賞
  4. Microsoft Word / Excel
  5. リモートデスクトップ
  6. 簡単な画像編集 (トリミングやリサイズ)

という感じになります。特に最初の二つが八割以上を占める利用になっています。

[イメージ]CQ57 の Windows エクスペリエンスインデックス

Windows エクスペリエンスインデックス は 2.8。やはりハードウェアは性能的に「それなり」と感じる時もまれにありますが、上述の利用傾向であれば、必要十分という感じです。

ちなみに ThinkPad Edge 14 はプロセッサ:6.5・メモリ:5.5・グラフィック:4.3・ゲームグラフィック:5.1・ハードディスク:5.8 でした。

ディスプレイの品質自体は MacBook Pro / ThinkPad Edge と並べて比べると若干見劣りするかもしれませんが、大きくて十分に見やすく、やはり大きなモニターにして正解でした。

Windows 7

これまでは XP 止まりでしたが、ThinkPad Edge / Presario CQ57 共に Windows 7 がインストールされています。

Windows Vista はほとんど触ったことがありません。セットアップを頼まれたりしたので、全くなかったわけではありませんが、会社でも導入されていなかったこともあって、日常的に触れる機会はありませんでした。ですので、実質的に Windows Vista はスキップして Windows XP から Windows 7 へ切り替えたことになります。

Aero と呼ばれるアピアランスは悪くないです。Windows XP の Luna は、常用するにはビビッドすぎましたが、Windows 7 の Aero はそんな印象は感じません。

[イメージ]Windows 7 のデスクトップ。私が利用するときはブラウザ動作検証が多いので、主要ブラウザがタスクバーに追加されています。

タスクバーは「クイック起動」と統合されて、Mac OS X の Dock に近い動作をするようになっていますね。これは Vista からでしょうか。

アプリケーション単位でのグループ化も XP よりも強化されて、ラベルを非表示にすることで、縦表示に切り替えても不自然でなくなりました。

それほどヘビーに使い込んでいるわけではないので、例えば、コントロールパネルの構成がまだよく分かっていなかったりしますが、とりあえずこれまでのところ、XP よりも使いやすいという印象です。

スポンサーリンク

3/25