好き勝手に・げーあにん?

ファミコンと同い年の社会人ヌルオタの日記

autorelease を使うべきなんだと気づくまでに時間かかりすぎた

※2013/06/04 追記:今はARCの時代です。autoreleaseとかで悩んでないでARC使いましょう。過去のソースのメンテとかしてる人は頑張れ



autorelease をケチらずに使うべきなんだということにようやく気づいた、Objective-C 初心者の私が Google Objective-C Style Guide を読みつつ思考垂れ流し。

生成時に autorelease するのが望ましい


一時的なオブジェクトを新しく生成するときには、そのメソッドの後ろの方で個別に release するのではなく、オブジェクトの生成と同じ行で autorelease すること。

http://www.textdrop.net/google-styleguide-ja/objcguide.xml#%E7%94%9F%E6%88%90%E6%99%82%E3%81%AB_autorelease_%E3%81%99%E3%82%8B%E3%81%AE%E3%81%8C%E6%9C%9B%E3%81%BE%E3%81%97%E3%81%84

一時オブジェクトは必ず autorelease 。一時オブジェクトは必ず autorelease 。すごく重要だと思ったので二回言いました。一時オブジェクトも release してたら、[NSString stringWithFormat:] みたいな中で autorelease が呼ばれてるやつと混ざってきて、あっという間にどれが release 呼ぶものなのかわからなくなったorz

あと、クラスメソッドで生成するようなやつは、autorelease を呼んだ状態で返すとか統一しないとダメだ。あっという間にどれが release 呼b(以下略)。インスタンス生成するクラスメソッドは全部 autorelease。autorelease しないやつは alloc init 。

というルールに気づくまでに一週間かかりましたorz

autorelease してから retain する


新しいオブジェクトを変数に代入するときには、メモリリークを起こさないように最初に古いオブジェクトを解放する必要がある。これには「正しい」やり方がいくつかある。私たちは「autorelease してから retain する」という方法を選んだ。間違いにくいためだ。タイトなループでは、autorelease pool がいっぱいになって効率が少し悪くなることに注意しよう。しかし、私たちはこのトレードオフは許容できると考えた。

- (void)setFoo:(GMFoo *)aFoo {
  [foo_ autorelease];  // Won't dealloc if |foo_| == |aFoo|
  foo_ = [aFoo retain]; 
}
http://www.textdrop.net/google-styleguide-ja/objcguide.xml#autorelease_%E3%81%97%E3%81%A6%E3%81%8B%E3%82%89_retain_%E3%81%99%E3%82%8B

他の正しいやり方もメモ。

- (void)setFoo:(GMFoo *)aFoo {
  [aFoo retain]; 
  [foo_ release];
  foo_ = aFoo; 
}
- (void)setFoo:(GMFoo *)aFoo {
  if (aFoo != foo_) {
    [foo_ release];
    foo_ = [aFoo retain]; 
  }
}

autorelease 使うのに統一しよう……間違いにくいの重要だった(何かやらかしたらしい)。つか、単純な setter 定義を間違えずに書くという意味では、@property(retain, nonatomic) が一番良いような気はする。

Objective-C++のコードを書いているときには、Objective-Cの例外を投げるとスタックベースのオブジェクトは解放されないということを認識しておこう。

http://www.textdrop.net/google-styleguide-ja/objcguide.xml#%E4%BE%8B%E5%A4%96%E3%82%92%E6%8A%95%E3%81%92%E3%82%8B%E3%81%AE%E3%82%92%E3%82%84%E3%82%81%E3%82%8B

これは知らないと危なすぎる……

以下の理由から、ドット記法を使ってプロパティにアクセスすることを禁止する。

これはデリファレンスしている型をわかりにくくしてしまう。[foo setBar:1] というのをみれば、Objective-Cのオブジェクトを操作しているとすぐにわかる。しかし、foo.bar = 1 というのをみても、fooがオブジェクトなのか、構造体や共用体なのか、C++のクラスなのかわからない。

http://www.textdrop.net/google-styleguide-ja/objcguide.xml#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3

以下の理由の2番目だけピックアップしてみた。他の3つの理由は「まぁ別にいいかな」と思えるんだけど、objc なんだか C/C++ なんだかわからなくなるのは我慢できなかった。ただでさえ、Cの上に全然文法が違う言語が乗っかっててキモイのに。


ようやく、Objective-C に慣れてきたんだけど、ほとんど C++ で書いている罠。Objective-C++ はコンパイルが極端に遅くなるとか、Wikipedia に書いてあるんだけど、手元で軽く検証したけど全然変わらないんだよなぁ‥‥どうやったら極端に遅くなるんだろう。


[ ] がウザイ以外は、割といい言語かもしれないと思い始めた。文法にさえなれれば割と好きになれるのかもしれない。メソッドチェインが必要な場面が多いのに、いちいち括弧で括るのは慣れてもツライ気もする。命名規則を守ってるとタイプ量もやたら多くてあんまり嬉しくなかったり……やっぱり好きになれないかも。