Sabes que en Cocoa existe esto, por ejemplo puedes crear un UIView
y hacer:
view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
Tengo una costumbre UIView
con varios estados, que he definido de enum
esta manera:
enum DownloadViewStatus {
FileNotDownloaded,
FileDownloading,
FileDownloaded
};
Para cada subvista creada, configuro su tag
:subview1.tag = FileNotDownloaded;
Luego, tengo un configurador personalizado para el estado de la 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 de enumeración.
¿Hay una manera de hacerlo?
(subview.tag == viewStatus)
ve mal para mí. Debería serlo((subview.tag & viewStatus) != 0x0)
, a menos que solo desee verificar la coincidencia exacta. En cuyo caso, en primer lugar, no necesitaría una máscara de bits, sino una simple enumeración antigua. Vea la segunda mitad de mi respuesta.Respuestas:
Declaración de máscaras de bits:
Como alternativa a la asignación de valores absolutos (
1
,2
,4
, ...) se puede declarar máscaras de bits (cómo éstos se llaman) como este:typedef enum : NSUInteger { FileNotDownloaded = (1 << 0), // => 00000001 FileDownloading = (1 << 1), // => 00000010 FileDownloaded = (1 << 2) // => 00000100 } DownloadViewStatus;
o usando macros
NS_OPTIONS
/ ObjC modernosNS_ENUM
:typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) { FileNotDownloaded = (1 << 0), // => 00000001 FileDownloading = (1 << 1), // => 00000010 FileDownloaded = (1 << 2) // => 00000100 };
(consulte la respuesta de Abizern para obtener más información sobre este último)
El concepto de máscaras de bits es (normalmente) definir cada valor de enumeración con un solo conjunto de bits.
Por lo tanto
OR
, la obtención de dos valores hace lo siguiente:DownloadViewStatus status = FileNotDownloaded | FileDownloaded; // => 00000101
que es equivalente a:
00000001 // FileNotDownloaded | 00000100 // FileDownloaded ---------- = 00000101 // (FileNotDownloaded | FileDownloaded)
Comparación de máscaras de bits:
Una cosa a tener en cuenta al comparar 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
status
es igualFileNotDownloaded
, puede usar:BOOL equals = (status == FileNotDownloaded); // => false
que es equivalente a:
00000101 // (FileNotDownloaded | FileDownloaded) == 00000100 // FileDownloaded ----------- = 00000000 // false
Comprobando "membresía":
Si desea verificar si
status
simplemente contieneFileNotDownloaded
, debe usar:BOOL contains = (status & FileNotDownloaded) != 0; // => true 00000101 // (FileNotDownloaded | FileDownloaded) & 00000100 // FileDownloaded ----------- = 00000100 // FileDownloaded != 00000000 // 0 ----------- = 00000001 // 1 => true
¿Ves la sutil diferencia (y por qué tu actual expresión "si" probablemente sea incorrecta)?
fuente
FileNotDownloaded = (0x1 << 0), // => %...00000001
etc.NS_OPTIONS
en aras de la integridad.Si bien @Regexident ha proporcionado una respuesta excelente, debo mencionar la forma moderna de Objective-C de declarar opciones enumeradas con
NS_OPTIONS
:typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) { FileNotDownloaded = 0, FileDownloading = 1 << 0, FileDownloaded = 1 << 1 };
Referencia adicional:
fuente
enum DownloadViewStatus { FileNotDownloaded = 1, FileDownloading = 2, FileDowloaded = 4 };
Esto le permitirá realizar operaciones operativas y operaciones bit a bit de manera eficaz.
fuente
1 << 0
,1 << 1
,1 << 2
etc. Esto deja claro que está trabajando con los bits y máscaras.Función útil que puede utilizar para comprobar la máscara de bits para mejorar la legibilidad.
BOOL bitmaskContains(NSUInteger bitmask, NSUInteger contains) { return (bitmask & contains) != 0; }
fuente
(bitmask & contains) == contains
- funcionará incluso con cerocontains