retain, release と -fno-objc-arc

これまで UI パーツの使い方を割と丁寧におさえてきたが、ここら辺で cocoa (最近だと AppKit というのかな?)アプリの作成に慣れるために、個人的に試験的なアプリを作成している。

ARC をオフにするには

その際に「これはいくらなんでも説明不足なんじゃ?」と思ったのが、ARC の使い方。

まず、「現在ではデフォルトで ARC がオンになっている」みたいなことは書かれているが、では、どうやって ARC をオフにしていいのか?そうすることのメリットは?みたいな説明はほとんどなされていない。

いやあ、これだと、スニペットみたいなコードは書けても、アプリを作成する際に色々と不都合が起こると思う。

その説明はいったんおいて、実用的なことを先に書くと、ARC = オンになっている Obj-C プロジェクトである部分だけをオフにしたいならば、TARGETS -> Build Phase -> Compile Sources でオフにしたいファイルの Compiler Flags に -fno-objc-arc というオプションを与える

これで、このファイルに含まれるクラスの ARC は無効になる。
あるオブジェクトを保持したければ retain (メソッド)を、破棄したければ release (メソッド)を明示する。

上の例では AppDelegate にこのオプションを与えたが、多分、これはかなり実用的な例。
ワイが試験的に作成しているアプリはまだ構造はさほど複雑ではないので、WindowsController は AppDelegate に集約している。
この時、困ったのは、あるウィンドウを閉じた時、(ARC をオンにしていると)そのウィンドウを管理しているコントローラーの存在が、不安定なように見えたこと。
ウィンドウをクローズするというのは、ウィンドウオブジェクトが破棄されたのか、それとも見えなくなっているだけでどこかにあるのかなどいくつか可能性があると思うが、この時の挙動がはっきりしない。

例えば、あるウィンドウのコントローラー(のポインタ)を wc としたとき

if(wc = nil){
  //処理
}

のようなコードを書いても、思ったような処理ができなかった。

だが、ARC をそこだけオフにしてみたところ、今の所狙ったようで動作している。

問題は使い分け

ARC に関してある程度把握はできたが、だからと言って、以降、すべて ARC=オフ にしてコーディングするかといえば、そんなことはないと思う。

まだ慣れていないせいもあると思うが、生成したすべてのオブジェクトで参照カウンタを気にするのは大変負担のように思える。

具体的な使い分けに関しては(この記事以外、ほとんど和文の資料はないと思うが)

retain と release の関係について

を参照してください。

 

NSOutlineView と item

多層構造のデータ表示の仕方がわからない、と言っていたが、試行錯誤の末、できた。

Person – Child – GChild という階層を持つデータがあったとき、適切に実装すると以下のように表示が可能だ。

ポイントは、 item をうまく使うこと。

具体的には

-(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
    if(item){
        if([item isKindOfClass:[Child class]] ){
            Child *c = item;
            return [c.gchildren count];
        }
        if([item isKindOfClass:[Person class]] ){
            NSLog(@"this item is Person");
            return [[item children] count];
        }
        return 0;
    }else{
        return [self.objects count];
    }
}

などとする。

直感的には item = 行(インスタンス1つ)という理解でいいと思う。
トップ階層(item が定義できない)は、self.objects count などとしているわけですね。

参考

・ここでの質疑応答

item という概念がわからないというある人の問題提起に対して林さんが

私の場合ですが、実データを入れるクラスとOutlineのアイテムを別々のクラスにして、アイテムの方のクラスのプロパティに実データのクラスのインスタンスを入れるように実装したことがあります。アウトラインに表示する時にものによってそれに対応するデータのクラスが異なっていたので、アウトラインビューのデータソースのアイテムは表示のためのものと割り切りました。

と応えている。

これは考えてみれば当たり前の話で、NSOutlineView からしてみれば、どんなデータが要素になるかわからない。
だから、そこら辺はコーダーの方で処理してくれよ、という話になる。

・YouTube の動画

動画は流れを掴むのにちょうどいい。

31:53 TableColumn の identifier の設定。
36:30 NSOutluneView と管理クラスの結び付け(datasource 経由

あたりは「百聞は一見にしかず」でしょう。

・OsiriX/Horos/HorliX における NSOutlineView

調査中。

・NSTreeView を使う

この記事で NSTreeView を使っていた。
手が空いたら試す。

・公式解説