Deklarieren und Prüfen/Vergleichen von (Bitmasken-)Enums in Objective-C

Lesezeit: 4 Minuten

Benutzeravatar von thibaultcha
Thibaultcha

Sie wissen, dass es in Cocoa dieses Ding gibt, zum Beispiel können Sie eine erstellen UIView und TU:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Ich habe einen Brauch UIView mit mehreren Zuständen, die ich in einer definiert habe enum so was:

enum DownloadViewStatus {
  FileNotDownloaded,
  FileDownloading,
  FileDownloaded
};

Für jede erstellte Unteransicht setze ich ihre tag: subview1.tag = FileNotDownloaded;

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

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

Aber was ich versuche zu tunist dies zuzulassen:

subview1.tag = FileNotDownloaded | FileDownloaded;

So mein subview1 zeigt sich in zwei Zuständen meiner Ansicht. Derzeit wird es seit dem in keinem dieser beiden Bundesstaaten mehr angezeigt | Der Operator scheint die beiden Aufzählungswerte hinzuzufügen.

Gibt es eine Möglichkeit, das zu tun?

  • Dein (subview.tag == viewStatus) sieht für mich falsch aus. Sollte sein ((subview.tag & viewStatus) != 0x0), es sei denn, Sie möchten nur nach exakter Übereinstimmung suchen. In diesem Fall benötigen Sie überhaupt keine Bitmaske, sondern nur eine einfache alte Aufzählung. Siehe zweite Hälfte meiner Antwort.

    – Regexident

    23. April 2013 um 11:17 Uhr

Benutzeravatar von Regexident
Regexident

Bitmasken deklarieren:

Alternativ zur Zuweisung absoluter Werte (1, 2, 4…) können Sie deklarieren Bitmasken (wie diese heißen) so:

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

oder mit modernen ObjC’s NS_OPTIONS/NS_ENUM Makros:

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

(Weitere Informationen zu letzterem finden Sie in Abizerns Antwort)

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

Somit ORDas Verknüpfen zweier Werte bewirkt Folgendes:

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

was äquivalent ist zu:

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

Vergleich von Bitmasken:

Beachten Sie bei der Überprüfung von Bitmasken Folgendes:

Prüfung auf exakte Gleichheit:

Nehmen wir an, dass der Status wie folgt initialisiert wird:

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

Wenn Sie überprüfen möchten, ob status gleich FileNotDownloadedkönnen Sie verwenden:

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

was äquivalent ist zu:

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

Suche nach “Mitgliedschaft”:

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

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

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

Sehen Sie den feinen Unterschied (und warum ist Ihr aktueller “if”-Ausdruck wahrscheinlich falsch)?

  • @Abizern: Danke! Ich dachte, diese Frage hätte ein bisschen mehr Erklärung verdient, als zuvor bereitgestellt wurde.

    – Regexident

    23. April 2013 um 11:19 Uhr

  • Ja, aber Sie formatieren die Binärwerte als Hexadezimalwerte (mit vorangestelltem 0x). Bitmasken arbeiten auf Bitebene. Einfacher Fehler, ich bin sicher, Sie haben es nicht einmal bemerkt. Aber jemand könnte sich das ansehen und fälschlicherweise annehmen, dass Sie maximal 8 Optionen pro Aufzählung haben können, wenn Sie tatsächlich maximal 32 verschiedene Optionen haben können. Korrektur: FileNotDownloaded = (0x1 << 0), // => %...00000001 usw.

    – Michael Zimmermann

    28. November 2013 um 20:49 Uhr

  • Apple bietet ein wunderbares Paar Makros NS_ENUM und NS_OPTION für Enum- und Bitmasken-Deklarationen. Benutze sie. Auf der NSHipster-Website finden Sie einige gute Beschreibungen.

    – uchuugaka

    29. November 2013 um 15:54 Uhr

  • Voll bewusst von ihnen. 😉 (Siehe Abizerns Antwort) Wie auch immer, eine Variation mit hinzugefügt NS_OPTIONS der Vollständigkeit halber.

    – Regexident

    1. Dezember 2013 um 20:25 Uhr

  • Recht. Ich verstehe, was du mit Überläufen meinst. Vielleicht sollte es einfach sein ((status & FileNotDownloaded) == FileNotDownloaded) also tag es sind nur zwei Ergebnisse möglich.

    – uchuugaka

    20. Januar 2014 um 23:40 Uhr


Benutzeravatar von Abizern
Abizern

Während @Regexident eine hervorragende Antwort geliefert hat, muss ich die moderne Objective-C-Methode erwähnen, mit der Enumerated-Optionen deklariert werden NS_OPTIONS:

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

Weitere Referenz:

  • Ja, die Makros NS_ENUM und NS_OPTION sind großartig.

    – uchuugaka

    29. November 2013 um 15:55 Uhr

enum DownloadViewStatus {
  FileNotDownloaded = 1,
  FileDownloading = 2,
  FileDowloaded = 4
};

Auf diese Weise können Sie bitweise ORs und ANDs effektiv ausführen.

  • Die Standardmethode zum Definieren der Werte ist 1 << 0, 1 << 1, 1 << 2 usw. Dadurch wird deutlich, dass Sie mit Bits und Masken arbeiten.

    – Mike Weller

    23. April 2013 um 10:58 Uhr


  • @AhmedAlHafoudh: Der Artikel geht jedoch nicht auf das zweite Problem von OP ein: das Arbeiten mit Bitmasken (im Gegensatz zu ihrer einfachen Deklaration). Siehe meine Antwort.

    – Regexident

    23. April 2013 um 11:15 Uhr

Nützliche Funktion, die Sie zur Bitmaskenprüfung verwenden können, um die Lesbarkeit zu verbessern.

BOOL bitmaskContains(NSUInteger bitmask, NSUInteger contains) {
    return (bitmask & contains) != 0;
}

1418180cookie-checkDeklarieren und Prüfen/Vergleichen von (Bitmasken-)Enums in Objective-C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy