web-dev-qa-db-ja.com

Objective-Cでの(ビットマスク)列挙の宣言とチェック/比較

Cocoaにはこのことがあることを知っています。たとえば、UIViewを作成して次のことができます。

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

次のようにUIViewで定義した複数の状態を持つカスタムenumがあります。

enum DownloadViewStatus {
  FileNotDownloaded,
  FileDownloading,
  FileDownloaded
};

作成されたサブビューごとに、tagsubview1.tag = FileNotDownloaded;を設定します

次に、私は次のことを行うビューステート用のカスタムセッターを持っています:

for (UIView *subview in self.subviews) {
  if (subview.tag == viewStatus)
    subview.hidden = NO;
  else
    subview.hidden = YES;
}

しかし、私がやろうとしていること、これを許可することです:

subview1.tag = FileNotDownloaded | FileDownloaded;

したがって、私のsubview1は、ビューの2つの状態で表示されます。現在、|演算子は2つの列挙値を追加しているように見えるため、これらの2つの状態のいずれにも表示されません。

それを行う方法はありますか?

76
thibaultcha

ビットマスクの宣言:

絶対値(124、…)次のように宣言できますビットマスク(これらの呼び出し方法):

typedef enum : NSUInteger {
  FileNotDownloaded = (1 << 0), // => 00000001
  FileDownloading   = (1 << 1), // => 00000010
  FileDownloaded     = (1 << 2)  // => 00000100
} DownloadViewStatus;

または、最新のObjCのNS_OPTIONS/NS_ENUMマクロ:

typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) {
  FileNotDownloaded = (1 << 0), // => 00000001
  FileDownloading   = (1 << 1), // => 00000010
  FileDownloaded    = (1 << 2)  // => 00000100
};

(後者の詳細については Abizernの答え を参照)

ビットマスクの概念は、(通常)単一のビットセットで各列挙値を定義することです。

したがって、2つの値をORingすると次のことが行われます。

DownloadViewStatus status = FileNotDownloaded | FileDownloaded; // => 00000101

次と同等です:

  00000001 // FileNotDownloaded
| 00000100 // FileDownloaded
----------
= 00000101 // (FileNotDownloaded | FileDownloaded)

ビットマスクの比較:

ビットマスクをチェックする際に留意すべきこと:

正確な同等性の確認:

ステータスが次のように初期化されると仮定しましょう:

DownloadViewStatus status = FileNotDownloaded | FileDownloaded; // => 00000101

statusequalsFileNotDownloadedかどうかを確認したい場合は、次を使用できます。

BOOL equals = (status == FileNotDownloaded); // => false

次と同等です:

   00000101 // (FileNotDownloaded | FileDownloaded)
== 00000100 // FileDownloaded
-----------
=  00000000 // false

「メンバーシップ」の確認:

statusが単にに含まれるFileNotDownloadedを含むかどうかを確認する場合は、以下を使用する必要があります。

BOOL contains = (status & FileNotDownloaded) != 0; // => true

   00000101 // (FileNotDownloaded | FileDownloaded)
&  00000100 // FileDownloaded
-----------
=  00000100 // FileDownloaded
!= 00000000 // 0
-----------
=  00000001 // 1 => true

微妙な違いをご覧ください(そして、なぜ現在の「if」式がおそらく間違っているのでしょうか)?

272
Regexident

@Regexidentは素晴らしい答えを提供してくれましたが、NS_OPTIONS

typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) {
  FileNotDownloaded = 0,
  FileDownloading   = 1 << 0,
  FileDownloaded    = 1 << 1
};

詳細なリファレンス:

19
Abizern

読みやすくするためにビットマスクチェックに使用できる便利な関数。

BOOL bitmaskContains(NSUInteger bitmask, NSUInteger contains) {
    return (bitmask & contains) != 0;
}
1
Renetik
enum DownloadViewStatus {
  FileNotDownloaded = 1,
  FileDownloading = 2,
  FileDowloaded = 4
};

これにより、ビット単位のORとANDを効果的に実行できます。

1
mah