objective-c c cocoa enums bitmask

objective c - Declarar y verificar/comparar(enmases de bit-) enum en Objective-C



cocoa enums (3)

Sabes que en Cocoa hay algo así, por ejemplo, puedes crear un UIView y hacer:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

Tengo una UIView personalizada con múltiples estados, que he definido en una enum como esta:

enum DownloadViewStatus { FileNotDownloaded, FileDownloading, FileDownloaded };

Para cada subvista creada, configuro su tag : subview1.tag = FileNotDownloaded;

Entonces, tengo un setter personalizado para el estado de vista que hace lo siguiente:

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

Pero lo que estoy tratando de hacer es permitir esto:

subview1.tag = FileNotDownloaded | FileDownloaded;

Entonces mi subview1 aparece en dos estados de mi vista. Actualmente, no aparece en ninguno de esos dos estados ya que | el operador parece agregar los dos valores enum.

¿Hay una manera de hacer eso?


Declarando máscaras de bits:

Como alternativa a la asignación de valores absolutos ( 1 , 2 , 4 , ...), puede declarar bitmasks (cómo se llaman) así:

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

o utilizando las macros NS_OPTIONS / NS_ENUM modernas de NS_OPTIONS :

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

(ver la respuesta de Abizern para más información sobre este último)

El concepto de máscara de bits es (generalmente) definir cada valor enum con un solo conjunto de bits.

Por lo tanto, OR ing dos valores hace lo siguiente:

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

que es equivalente a:

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

Comparando las máscaras de bits:

Una cosa a tener en cuenta al verificar contra las máscaras de bits:

Comprobando la igualdad exacta:

Supongamos que el estado se inicializa así:

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

Si desea verificar si el status es igual a FileNotDownloaded , puede usar:

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

que es equivalente a:

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

Comprobando la "membresía":

Si desea verificar si el status simplemente contiene FileNotDownloaded , debe usar:

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

Vea la diferencia sutil (¿y por qué su expresión "si" actual es probablemente incorrecta)?


Mientras que @Regexident ha proporcionado una excelente respuesta, debo mencionar la forma moderna de Objective-C de declarar opciones NS_OPTIONS con NS_OPTIONS :

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

Referencia adicional:


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

Esto le permitirá realizar OR de forma bit y AND de manera efectiva.