リファクタリング

ARC+Blocks+llvm4.0時代のコード記述作法

このエントリーをはてなブックマークに追加
はてなブックマーク - ARC+Blocks+llvm4.0時代のコード記述作法

はじめに

ARC、Blocks、llvm4.0 Modern Objective-Cと、Objective-Cの記述方法はどんどんん変わっています。コードの記述量が減ったり、分かりやすいコードを書くことが出来る様になって来たものの、リーク、EXC_BAD_ACCESS(解放されたメモリにアクセスすることによるクラッシュ)が発生する危険があります。この記事では、2012年8月のリリースされた機能の時点で、わたしが採用している書き方のルールを紹介します。

iOS5 + weak最強

前提条件として、__weakが使用出来るiOS5での状況について記述しています。UI要素の変更の為にBlocksをコールバックで使う状況で、iOS4+ARC+Blocksで完全に問題が起きないコードを書くのは結構大変です。

決まりを作る

それで実際にプログラムを作成するのですが、その時その時でベストな方法を選べば良いのですが、それだと、作っている人のスキルに依存するため、ルールを決めてしまって、そのルールを守る様にしています。特にこれはスキルや、言語理解の異なるチームで行う際には重要ですね。

ARC+Blocks+Xcode4.4での4つの決まり

いかの4つの決まりを作成して運用を開始しています。

  1. ivarを作成せず、すべて@propertyを作成する
  2. 少し前までは、@interfaceに、ivarを作成するのが普通でしたが、最近は、@implementationに作成する方が、ヘッダファイルに不要な変数を入れないので普通になったと思います。Xcode4.4のllvm4.0から、synthesized by defaultというのが採用され、@synthesizeを書かなくても、

    このように記述することによって、

    上の@synthesizeが自動的にコンパイラによって補完されます。詳しくは、今日からライオンでも使える!Xcode4.4 Modern Objective-C Syntaxでコードをきれいにする方法 | Zero4Racer PRO Developer’s Blog の記事をご覧下さい。

    基本的にはすべて.mファイルに、無名カテゴリを使用して作成しますが、別のファイルからアクセスするプロパティは、ヘッダファイルに移動します。

    変数にアクセスする際は、self.mycount, _mycount 両方使用することが出来ますが、init系のメソッド内、また、dealloc内では、必ず_で始まるivarを使用します。

  3. Blocks内では、ivar、selfには決してアクセスしない
  4. これは、こうしなくてもうまくいく場合は確かにあります。blocksが、将来の実行のためにコピーされた時に、循環参照が起きる危険が発生します。通常、ブロックを作成したスレッドと同じスレッドで、連続してBlockを実行する状況では、Blockはコピーされないため、selfを使っていても循環参照しません。
    [IOS5]FOR (;;) を書くのをやめるいくつかの方法と、BLOCKS+ARCの考察 | Zero4Racer PRO Developer’s Blog この記事で少し説明しました。しかし、blocksを渡した先でどのように処理するかは分かりませんし、パフォーマンスのために、後から動作の方法を変えることもあります。ですから,blocksの中で self.と書くのは禁止します。そして_mycountなどの、ivarにアクセスすると、self->_mycountとみなされて、知らずにselfがretainされてしまい、循環参照が起きることがあります。なので、blocksの中でのivarの使用も禁止です。
    サンプルで、だめな記述の例(チェックで発見したもの)を載せときます。

  5. Blocks内でアクセスする用に__weakで、wselfポインタを作成する
  6. (2)で禁止したselfへのアクセスの代わりに、__weak型のselfポインタを作成します。

    こんな感じです。クラスは、現在のクラスの型ですね。そして、blocksの中では、ivarにアクセスせず、wselfに対するプロパティでアクセスします。修正後はこんな感じです。

    Blocks内すべてを書き換える必要があるので、検索で”^{“の物をすべて検索して、一つづつ修正していきます。

    リファクタリング
    リファクタリング

    注意すべきなのが、以前は、wself->_mycountのように、->を使って、ポインタのivarにアクセスすることが出来ていましたが、llvm4.0から、__weak ポインタに対しては、-> でのivarのアクセスが出来なくなりました。

    ですから、(1)のようにすべてpropertyにする必要がある訳ですね。

  7. IBOutletは、@propety (weak) で接続する
  8. こちらはおまけですが、IBOutletで、Storyboardと連結するときですが、既にそれぞれのコンポーネントは、viewに追加されているため、weakで接続するのが好ましいです。なので、IBOutletは、以下の様に記述します。

まとめ

参考にしたサイトは、Appleのドキュメントと、kishikawa katsumi (k_katsumi) on Twitter さんの、iPhone_dev_jpでのスライドです。

突っ込みどころもたくさんあると思いますので、何かあったらTomohisa Takaoka (tomohisa) on Twitter か、コメントで。

Comments

comments

Powered by Facebook Comments

One comment

  1. Pingback: [Objective-C] libextobjc の @weakify と @strongify について | Zero4Racer PRO Developer's Blog

Post a comment

You may use the following HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">