Month of 5月, 2010

子ノードには手を出すな(NSTreeController)

in

このところまたOutlineView+TreeControllerやってます。それでひとつ気づいたことをメモ。

"ツリーコントローラーにストアしているデータをすべてinsertしてもツリー構造にはならない"ということ。読み込んだ子ノードのデータをTreeControllerにinsertすると(親ノードの配下にも表示されますが)親ノードと兄弟のように表示されちゃいますね。ググってみたら、Fetch Predicateに”parent == nil"を指定する(cocoadev:NSTreeController)のが慣例みたいなんですが知りませでした。データの読み込みを確認しながらようやくわかった次第。要するに親ノードが持っている子ノードの展開はTreeControllerが内部で実行することになっているようでプログラムからは親ノードさえadd/insertしてやれば良いようです。当然バインドの場合でも上記の例のようにPredicateを指定する必要があるようです。(Appleの公式ドキュメントとしてどこかに書かれているのかな?)

NSManagedObjectContext *moc = [self managedObjectContext];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
NSArray* sortDesc = [NSArray arrayWithObject:
  [[[NSSortDescriptor alloc] initWithKey:@"orderNo" ascending:YES] autorelease]];

[fetch setEntity:
  [NSEntityDescription entityForName:@"ChildNodeEntity" inManagedObjectContext:moc]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"isLeaf == 0"]];
[fetch setSortDescriptors:[self sortDesc]];

NSError *err     = nil;
NSArray *results = [moc executeFetchRequest:fetch error:&err];
if ((err) || (results == nil))
{
  [NSApp presentError:err];
  return;
}

NSUInteger index = 0;

for (ChildNodeEntity *node in results)
{
  [treeController insertObject:node atArrangedObjectIndexPath:
    [NSIndexPath indexPathWithIndex:index]];
  index = index + 1;
}

まあ、実際にやりたかったのはノードの表示順を一定に保つことでCocoaDevのリンクnstreecontroller-and-core-data-sortedにもあったようにノードの中になんらかの方法で順序を示す数値を仕込んでおけばOK。子ノードの展開はTreeControllerお任せになるのでSortDescriptorをバインドする必要もあります。ロード時に特別の処理がなければ僕のコードのようにガリガリコードを書くのは不作法で、やっぱりバインドしたほうがスマートですね。

ちゃんと考えた方がいいというハナシ。

in

今日はHDDがやばそうなサーバのバックアップ機のセットアップ。大方できあがって最後CPANモジュールのインストールの段になってどうしてもインストールできません。どうやら全部プロキシでハネられているようなんですが...いや絶対間違ってないぞ!と思いつつ格闘するも2時間。とうとう諦めて、本番サーバのConfig.pmをもってきてdiff。

# diff Config.pm Config.pm_BAK
14c14
<   'ftp_proxy' => q[http://xxx.x.x.xxx:8080/],
---
>   'ftp_proxy' => q[ftp://xxx.x.x.xxx:8080/],

いや、ftp_proxyなんだから...ftpでしょ?あー疲れた一日。

EVP_*系APIでのBlowFish実装

パスワードを保存するアプリを作るため以前使ったことのあるBlowFishのmanを読み直していたら、BF_*系の関数を直接使うんじゃなくてもっと高レベルのEVP_EncryptInitとかを使いなよって書いてあったので忠告に従いこちらを使うべく調べてみました。BF_*系と違うのは暗号・復号に際して必要な情報を追跡するためのコンテキスト情報EVP_CIPHER_CTXを維持していく必要があるのが大きな違いになります。処理は

  1. 暗号コンテキストの初期化
  2. 暗号化方式の決定と初期化
  3. 暗号・復号処理
  4. 暗号コンテキストの解放

といったフローでそれほどステップは多くないカンジ。まず、暗号コンテキストの初期化は