Nullarihyon 1.7

Xcode8にNullability Violationをチェックする機能が入ると聞いて一晩泣き明かしましたが、それはそれとしてちまちま開発を続けています。Xcode8との比較はまたそのうち。

github.com

Nullarihyon 1.6では「nonnullなインスタンス変数に代入があるかどうかを確認する機能」を実装しています。

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

@property (nonatomic) NSString *name;
@property (nonatomic) NSString *address;

- (instancetype)initWithName:(NSString *)name address:(NSString *)address;

@end

@implementation Person

- (instancetype)initWithName:(NSString *)name address:(NSString *)address {
  self = [self init];

  self.name = name;
  // addressを設定するのを忘れている

  return self;
}

@end

NS_ASSUME_NONNULL_END

こういうプログラムがあったときに、警告を出すようになっています。init的なメソッド全てで検査すればいい気もしますが、ひとまずはオプトインで __attribute__((annotate("nlh_initializer")))がついたものだけ検査します。

- (instancetype)initWithName:(NSString *)name address:(NSString *)address __attribute__((annotate("nlh_initializer")));

などとつけましょう。

この属性がついたメソッドでは、

  • 全てのnonnullなインスタンス変数に何かを代入する
  • 別の__attribute__((annotate("nlh_initializer")))なメソッドを呼ぶ

のどちらかの条件が成り立っていないといけません。そうでない場合は、nonnullなインスタンス変数が初期化されずに残っているとみなして、警告を出します。

この機能で、Nullarihyonで検査してokなプログラムは(キャストによって確信犯的に導入されたもの除けば)nonnullなメソッド・プロパティがnilを返すことはないことが保証できるようになったはずです。nonnullをつけたい場合には、

  1. Nullarihyonをインストール、セットアップする
  2. 型にnonnullをつけて回る
  3. initにattributeをつける
  4. コンパイルして、警告をちまちま直す

とすれば、かなり安全に作業が進められます。逆に言うと、この「initでnonnullなインスタンス変数が初期化されずに残る問題」はかなり厄介で危険なので、Nullarihyonを使わないのであれば気軽にnonnullとか付けるべきではないとも言えます(強気)。

homebrewで簡単に入るので、ぜひおためしください。

1.7の話

1.7では、検査したいクラスのフィルタに正規表現が書けるようになりました。nullfilter

/ViewController/

などと書くと、クラス名にViewControllerを含むものだけ検査するようになります。

本当は、negationが書きたくて、例えば

!/ViewController/
!/^NS/

などと書いて「ViewControllerとNSなんとか以外のクラスを検査する」としたいのですが、フィルタの意味を考え込んでしまってまだできていません。