it-swarm.com.de

Deklarieren und Überprüfen / Vergleichen von (Bitmasken-) Aufzählungen in Objective-C

Sie wissen, dass es in Cocoa dieses Ding gibt, zum Beispiel können Sie ein UIView erstellen und Folgendes tun:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Ich habe ein benutzerdefiniertes UIView mit mehreren Zuständen, die ich in einem enum wie folgt definiert habe:

enum DownloadViewStatus {
  FileNotDownloaded,
  FileDownloading,
  FileDownloaded
};

Für jede erstellte Unteransicht lege ich ihr tag fest: subview1.tag = FileNotDownloaded;

Dann habe ich einen benutzerdefinierten Setter für den Ansichtsstatus, der Folgendes ausführt:

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

Aber was ich versuche zu tun, ist dies zu erlauben:

subview1.tag = FileNotDownloaded | FileDownloaded;

Mein subview1 Erscheint also in zwei Zuständen meiner Ansicht. Derzeit wird es in keinem dieser beiden Zustände angezeigt, da der Operator | Die beiden Aufzählungswerte zu addieren scheint.

Gibt es eine Möglichkeit, das zu tun?

76
thibaultcha

Bitmasken deklarieren:

Alternativ zur Zuweisung von Absolutwerten (1, 2, 4,…) Können Sie bitmasks (wie diese heißen) wie folgt deklarieren:

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

oder mit modernen ObjCs NS_OPTIONS/NS_ENUM Makros:

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

(Siehe Abizerns Antwort für weitere Informationen zu letzterem)

Das Konzept von Bitmasken besteht darin, (normalerweise) jeden Aufzählungswert mit einem einzelnen Bit-Satz zu definieren.

Daher bewirkt OR das Eingeben von zwei Werten Folgendes:

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

was äquivalent ist zu:

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

Bitmasken vergleichen:

Beachten Sie Folgendes, wenn Sie nach Bitmasken suchen:

Überprüfung auf exakte Gleichheit:

Nehmen wir an, dass der Status folgendermaßen initialisiert wird:

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

Wenn Sie überprüfen möchten, ob status gleich FileNotDownloaded ist, können Sie Folgendes verwenden:

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

was äquivalent ist zu:

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

Überprüfung auf "Mitgliedschaft":

Wenn Sie überprüfen möchten, ob status nur FileNotDownloaded enthält, müssen Sie Folgendes verwenden:

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

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

Sehen Sie den subtilen Unterschied (und warum ist Ihr aktueller "wenn" -Ausdruck wahrscheinlich falsch)?

272
Regexident

Während @Regexident eine hervorragende Antwort geliefert hat, muss ich die moderne Objective-C-Methode zur Deklaration von Aufzählungsoptionen mit NS_OPTIONS Erwähnen:

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

Weitere Referenz:

19
Abizern

Nützliche Funktion, die Sie zur Überprüfung der Bitmasken verwenden können, um die Lesbarkeit zu verbessern.

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

Auf diese Weise können Sie bitweise ODER- und UND-Verknüpfungen effektiv ausführen.

1
mah