このブログを停止いたします

このブログの更新を停止し、新しくこたつつきみかん rev.2で再開したいと思います。理由を簡潔に列挙致します。

  • きっかけはブログデータ消失事件
  • 相対的なブログ記事の情報価値の低下
  • 以前の流れを断ち切って、新規一転して記事を投稿したい
  • 「わかりやすい情報」から「高度な情報」へ

このところ思っていたのは、もはや Objective-C の情報が少ない時代は終わりを迎え、本屋に行ったりググればすぐに日本語のわかりやすい情報が手に入るようになりました。わかりやすい情報を書き綴っていたこのブログの役目もそろそろ終わりとして良い頃合いでしょう。

それと同時に、もう一つ思ったのは、WEBにはわかりやすい情報やすぐに使える情報が溢れかえっており、より専門的な高度な情報だったり、正確な情報というのが今ひとつ見えてきません。英語で検索するといい文章が見つかることが多いのですが、日本語の検索結果はあまり満足していないのが現状です。

もうプログラムの基本的なことを語るのは十分でしょう。これからはより正確で高度な情報を配信していこうと思います。

このブログはずっと残しておくつもりですが、情報が古いので注意してください。また、しばらくしたらコメント欄を封鎖しようと思います。

いままでありがとうございました。

ブログデータ消失しました

さくらのVPS新プランに移行中、うっかり既存のプランの方のサーバーをセットアップしてしまい、ここ最近のブログデータと画像を消去してしまいました。

画像データはバックアップが無かったかもしれないので、現在どのようにするか検討中です。。。

古い情報はあまり役に立たなくなってきているので、そろそろ一度区切りを付けてもいいかもしれません。

ffmpegの再配布について

以前、nConverterというソフトを作ってとりあえずリリースしましたが、その後、自分が使わないので放置し続けていて、OS X 10.6 でうまく動作しない状態でした。

最近なんとなく気が向いたので、うまく動かない部分を修正していっているのですが、主な修正箇所は NSCollectionView がうまく表示されないという謎な箇所でした。ログに unlockfocusなんとか と出るだけで、かなり謎でしたが、NSCollectionViewItem の View に乗っている NSImageView の中の NSProgressIndicator が原因でした。結局何をしても NSProgressIndicator が邪魔するようだったので、あまり必要もないので削除して対処しました。

ついでに動画の変換もうまくいかなかったので、原因を調査していると、どうやらmovtowavに変なバグがあって、どうしてもうまく動きませんでした。movtowavを配っていたサイトもなくなってしまったので、ffmpegのみでエンコードできないかと試すと、最新のffmpegなら十分エンコードできそうでした。(以前のffmpegはffmpegXのffmpegを使っていました)

そこで、ffmpegのみでエンコードできるように改良して、とりあえず修正は完了したのですが、ここで大きな問題が発生しました。

iPhone用の動画はmp4でh264/AACなのですが、この音声コーデックのAACエンコーダであるlibfaacを付けてffmpegをビルドすると、ライセンス上 ffmpeg を再配布できなくなってしまい、nConverterに同梱できなくなってしまうのです。

ffmpegはユーザーにビルドしてもらうという手もありますが、それはなかなか敷居が高く、しかもバージョンによってオプションの指定が変わったりもするので、そうするのは難しいです。

そんなわけで、せっかく修正したものを、どうやってリリースしようか迷っています。

なぜ iPhone プログラミングではデリゲートを多用するのか

iOS / iPhone プログラミングでは、デリゲートをよく見かけることになります。どうしてこんなに見かける羽目になってしまったのでしょうか。それを考えてみることにします。

まず1つ。iPhone アプリケーションでもっとも基本的なユーザーインターフェースは、おそらくテーブルビュー ( UITableView )になるのではないでしょうか。このテーブルビューの実装では、少なくとも2つのデリゲートを実装することになります。それは、UITableViewDataSource と UITableViewDelegate であり、1つのクラスで両方のデリゲートを実装してしまえば、1つのクラスしかできませんが、それでもテーブルビュー1つにつき、2つのデリゲートを実装する必要があるのです。

そして2つ目。アプリケーションにも依りますが、 NSURLConnection ではデリゲートで通信のやりとりをします。つまり、ネットワークから何かリソースを取得するようなプログラムの場合、この NSURLConnection によってデリゲートを使う必要が出てくるわけです。

他にも UIAlert など、デリゲートが出てくる場面はたくさんあります。その結果、iOS / iPhone プログラミングでは、デリゲートを多用する必要が出てきてしまっているのでしょう。

一方で、OS X はどうなっているのかと言えば、そもそも UI の基本がテーブルビューとは限らないので、iOS ほどテーブルビューを使いません。そして何よりも、 OS X では Cocoa Biding が利用できるわけで、outlet / action 接続がほとんど無くなるだけでなく、テーブルビューでデータソースをデリゲートにする必要もなくなり、デリゲートの数が少なくなります。

iOS / iPhone で Cocoa Binding が無いのは、おそらくオーバーヘッドが大きいし、バインドして値を同期させるほどの処理性能が iPhone にはないからだと考えておりますが、よりデバイスが進化した数年後には、Cocoa Binding が iPhone でも使えるようになっていてもおかしくはないと思います。

Objective-C の名前空間について

Objective-C には名前空間がありません。そのことについて、不満を述べるプログラマが少なからず居るようですが、私はそんなことは思いません。なぜなら、名前空間は便利こそあれど、本質的にプログラミングに関係することではないと思っているからです。

Objective-C のランタイムシステムや Cocoa フレームワークの名前は、衝突を防ぐために古典的な方法がとられているのは、すぐにわかると思います。それは、名前の前に接頭辞を付けることです。たとえば、NSObject であったら、NS の部分がそれにあたります。

もし名前空間の機能があれば、おそらくファイルの先頭で名前空間の使用を宣言すれば、それ以降に接頭辞を付けることなくクラス名を書くことができるでしょう。これによって、記述が少なくなり、打つ手間も省けるでしょう。ただし、Objective-C の命名規則では、先頭の二文字が省略できるにすぎませんが。要するに、名前空間があったとしても、それほど便利になるとは思えないというところです。Objective-C は、Cから比較的簡素な拡張のされ方をしている言語なので、極力言語に機能を追加しないほうがいいと、私は考えています。

そうは言うものの、無いものは不便と感じる方も居ますので、気休め程度に名前空間が無いメリットを紹介します。

それは、クラス名がユニークなので、とても検索しやすいことです。クラス名が String であったら、検索したときにほかの言語の情報が出てくるかもしれませんが、 NSString ならば、簡単に NSString の情報を探し出すことができます。ついでに言うと、Objective-C の長いメソッド名も、打つのは大変であれど、検索しやすくていいところもあります。逆に検索結果が少なすぎて絶望することもありますが。

このように、名前空間が無いからこそのメリットもありますので、そんなに悲観すべきことではないと思います。

今年はもっと記事書けるように頑張ります

新年、12月は記事を1エントリーも書かずに、ついに明けてしまいました。残念です。ここ最近、ブログの更新をサボっている感じになっていますので、月5エントリーペースで書きたいですね。

Objective-C のクイックリファレンスの方も、更新が途絶えてますが、今続きを書き始めているので、近日中に増えると思います。しかし、数ヶ月前から Interface Builder の記事を書きたくて仕方ないので、そちらを先に書き始めてしまうかもしれませんが。本当は、新しいXcodeが出てから書きたいのですが、なかなか出そうにないので、先に書いてしまう予定です。

Interface Builder に関する記事はとても少ない印象で、そして使っていない方が、もしかすると多数派なのかもしれないので、Inteface Builder のすばらしさを伝えられる記事にしたいです。

NSPredicate の使い方

NSPredicate の話を求めて、このブログへ訪れる方が多いようなので、NSPredicate の使い方を紹介しようと思います。

NSPredicate は、NSArray で要素をフィルターするための条件を表したり、Core Data で取ってくるデータの条件を表すためのクラスです。

NSPredicate を作成する方法として最も簡単なものが、predicateWithFormat です。これを用いると、NSPredicate 独自の記法ではありますが、自然な記述で条件を書くことができます。

Predicate の条件式の基本形は、”keyPath operator literal” です。それぞれには、次のようなものが入ります。

keyPath
キー値コーディングのキーパス。この値が条件の判定に利用されます。self 指定すると、そのオブジェクト自体の値が利用されます。(selfもキー値コーディングです)
operator
比較演算子が入ります。数値であれば、=, < , >, < =, >= 等、文字列であれば =, contains, like, startsWith, endsWith, in 等が使用できます。
literal
定数値を入れます。キーパスとの比較に用いられます。数値は直接書き、文字列の場合は ‘ ‘ や ” ” で括ります。また、配列を { e0, e1, … } のような形式で記述できます。

また、メソッド名に Format があるように、NSLogと同様に書式指定子が使用できます。ただし、Predicate 用に追加されている書式指定子 %K があります。これは、keypath の部分を指定する書式指定子で、キーパスを入れるところには %@ ではなく、 %K を使うことに注意しなければなりません。

具体的な例を見れば、すぐにわかると思いますので、いくつかの例を示します。

NSArray *strings = [NSArray arrayWithObjects:@"first", @"second", @"third", nil];
NSPredicate *predicate;

// 単純な比較
predicate = [NSPredicate predicateWithFormat:@"self = 'first'"];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { first }

// 書式指定子を利用した比較
predicate = [NSPredicate predicateWithFormat:@"%K = %d", @"length", 5];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { first, third }

// in 演算子の利用と、配列のリテラル値の入力方法
predicate = [NSPredicate predicateWithFormat:@"self in %@", [NSArray arrayWithObjects:@"first", @"second", nil]];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { first, second }

// contains 演算子の利用
predicate = [NSPredicate predicateWithFormat:@"%K contains %@", @"self", @"i"];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { first, third }

// like演算子と1オプションの利用
predicate = [NSPredicate predicateWithFormat:@"%K like1 %@", @"self", @"FIRST"];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { first }

また、not, and, or 等の演算子を利用できます。

predicate = [NSPredicate predicateWithFormat:@"not ( 1 <= length and length <= 5 )"];
NSLog( @"%@", [strings filteredArrayUsingPredicate:predicate] );
// { second }

演算子やPredicateの作成方法は、他にもあります。詳しくは、Predicate Programming Guide を御覧ください。

参考資料
Predicate Programming Guide
NSPredicate Class Reference

NSURLConnection+Blocks

まだあまり相手にされていない感じの Blocks ですが、使うことができるシーンは結構あります。

NSURLConnection を使用すると、簡単にWEBからリソースを取得できますが、多少記述が多くなってしまうのと、デリゲートによって処理が散らばってしまうのが問題です。そこで、Blocks を使って、よりモダンな書き方ができるようにしてみます。

今回は NSURLConnection にカテゴリとして追加することにしました。使い方はこんな感じになります。

 NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.lifeaether.com/"]];
[NSURLConnection sendRequest:request completeBlock:^( NSData *receivedData ) {
    NSString *html = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
    NSLog( @"%@", html );
    1;
} errorBlock:^( NSError *error ) {
    NSLog( @"%@", error );
}];

completeBlock がリソースの取得に成功したときに呼び出されるブロックです。引数に受信したデータが入っています。errorBlock が失敗したとき呼び出されるブロックです。引数にエラー内容が入ります。

カテゴリの実装です。
NSURLConnection+Blocks.h

#import <Foundation/Foundation.h>

@interface NSURLConnection (BlocksAddition)

+ (void)sendRequest:(NSURLRequest *)request completeBlock:( void (^)( NSData *receivedData ) )complete errorBlock:( void (^)( NSError *errror ) )error;

@end

NSURLConnection+Blocks.m

#import "NSURLConnection+Blocks.h"

@interface NSURLConnectionBlocksAddtionDelegate : NSObject {
@private
    NSMutableData *receivedData;
    void (^completeBlock)( NSData *receivedData );
    void (^errorBlock)( NSError *error );
}

- (id)initWithCompleteBlock:( void (^)( NSData *receivedData ) )compelete errorBlock:( void (^)( NSError *error ) )error;

@end

@implementation NSURLConnectionBlocksAddtionDelegate

- (id)initWithCompleteBlock:( void (^)( NSData *receivedData ) )compelete errorBlock:( void (^)( NSError *error ) )error
{
    self = [super init];
    if ( self ) {
        receivedData = [[NSMutableData alloc] init];
        completeBlock = [compelete copy];
        errorBlock = [error copy];
    }
    return self;
}

- (void)dealloc {
    [errorBlock release];
    [completeBlock release];
    [receivedData release];
    [super dealloc];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [receivedData setLength:0];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    [receivedData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    completeBlock( receivedData );
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    errorBlock( error );
}

@end

@implementation NSURLConnection (BlocksAddition)

+ (void)sendRequest:(NSURLRequest *)request completeBlock:( void (^)( NSData *receivedData ) )complete errorBlock:( void (^)( NSError *errror ) )error
{
    id delegate = [[[NSURLConnectionBlocksAddtionDelegate alloc] initWithCompleteBlock:complete errorBlock:error] autorelease];
    [self connectionWithRequest:request delegate:delegate];
}

@end

特に説明する部分はないかと思われますが、疑問が出そうなところを少し解説します。

sendRequest: メソッド内で NSURLConnectionBlocksAddtionDelegate インスタンスに autorelease していて、開放されるんじゃないかと思われる人がいるかもしれませんが、NSURLConnection は例外的に delegate を retain するので、開放される心配はありません。

initWithCompleteBlock: メソッド内で、引数のブロックを copy していますが、これはブロックが通常はスタック領域に確保され、関数から抜けだすと消失してしまうからです。copy することによってそれを回避します。それによって、releaseする必要も生じます。

MacBook Air 13インチ の使用レポート

MacBookAir 13インチ 128GB モデル メモリを4GB カスタマイズ を買ってから半月くらい経ちました。外出時かつ他のパソコン環境がないところでしか使わないので、まだあまり利用していませんが、電車の中で寝ていないときには大活躍しています。

いいところ

  • 起動が速い
  • 軽い
  • 画面が広い
  • キーボードが打ちやすい
  • SDカードが挿せる
  • バッテリーが持つ
  • 十分なスペック

わるいところ

  • キーボードの感覚
  • まれに画面が乱れて再起動せざるを得なくなる
  • CDが取り込めない
  • 文字がちっちゃい

いいところ – 詳細

見た目で驚き、持って驚き、そして起動して驚きます。起動速度がとにかく速いです。ばらつきがありますが、15〜30秒で起動します。本当に速い。

13インチなので、画面が十分な広さです。これなら、プログラミングも満足に行えます。長いメソッド名も、これでバッチリです。

SDカードを挿せます。デジカメの画像を簡単に取り込めるので iPhoto と連携して活躍します。

バッテリーが持ちます。開発作業なら、おそらく公式の7時間は持つことでしょう。ちゃんと測っていませんが、それくらいは持ちそうな気がします。

十分なスペックがあります。たいていの作業は、ストレス無く行うことができます。たまにひっかかりを感じたり、待ち時間を要する作業もありますが、この軽さ、バッテリーの持ちを考えると、とても素晴らしいです。

わるいところ – 詳細

キーをストロークしたときの感覚があまり良くありません。好みに依るところが大きいので、購入前に一度試してみましょう。感覚が悪いからと言って、打ちにくいわけではないので、実用上問題はないのかもしれません。

稀に画面が乱れて何もできなくなる現象が発生します。しかし、これは最近のアップデートで直ったかもしれません。

CDが取り込めません。ネットワークドライブから iTunes に読み込もうと思ったのですが、うまくできませんでした。調べてみると、著作権保護のかかったCDはネットワークドライブからインポートできないようです。

文字がやや小さいです。まだ許容範囲ですが、小さいなと感じる場面がたまにあります。

まとめ

どこへ行っても作業したくなる人に大変おすすめできます。iBook G4 12 inch を持っていた経験からすると、ポータビリティはとても重要で、とにかく、いつでも持ち運ぶ気にならなければ、ノートブックを買う意味がありません。

しかし、ポータビリティを重視しすぎると、スペックが十分でなかったり、バッテリーの持ちが悪かったりしますが、その点、この Air は絶妙なバランスを保っていると言えるでしょう。

11インチについて

軽いのはいいのですが、ややスペックと画面の広さ、そしてバッテリーの持ちに不満を感じそうだったので、13インチを選びました。迷っている方は、店頭で比較してから買うといいと思います。

MacBookAir を買いました

そろそろノートパソコンが欲しかったので、MacBookAir 13インチ 128GB モデルを買いました。メモリを4GBにカスタマイズしています。

まだあまり使用していないので、詳しいレビューはあとでしようと思いますが、私のMac環境のセットアップを書いていこうと思います。

1 アップデート

最初にソフトウェアアップデートをしました。

2 設定の移行

Mailは手動で設定し、Safariのブックマーク、アドレスブック、iCalのデータ等は、iPhoneを通して同期させることで、iMacから移行しました。他の設定は、それほどいじっていないので、必要になったら手動で設定しています。

3 アプリケーション入れる

growl
通知専門アプリケーション。いろんなアプリケーションが対応しているので、必ずインストールしておきたアプリケーション。
Adium
インスタントメッセンジャー
CotEdtior
さまざまなエンコーディングに対応した、シンプルなエディタ。コードのハイライト機能もある。
Google 日本語入力
「ことえり」に不満を感じる場合もあるので、必要に応じて使い分けます。
NetNewsWire
RSSリーダー。Google アカウントで管理します。iPhone版もある。
Yorufukurou
Twitter クライアント。
The Unarchiver
圧縮ファイル展開アプリケーション。さまざまな形式に対応している。
Xcode
開発ツール。言うまでもなし。
Xcode 4 Preview
プレビュー版
MacPorts
Mac版port
pTeX
TeX。portからインストールする。

4 データ移行

あまり移行するようなデータがないので、必要に応じてファイル共有をして取ってきます。

あまりカスタマイズしないで使っているため、こんな感じでいつもの環境になります。