Objective-C에서 (bitmask-) 열거 형 선언 및 확인 / 비교


79

Cocoa에는 이런 일이 있다는 것을 알고 있습니다. 예를 들어 다음을 생성 UIView하고 수행 할 수 있습니다 .

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

다음 과 같이 UIView정의한 여러 상태 의 사용자 정의가 있습니다 enum.

enum DownloadViewStatus {
  FileNotDownloaded,
  FileDownloading,
  FileDownloaded
};

생성 된 각 하위보기에 대해 tag다음을 설정합니다 .subview1.tag = FileNotDownloaded;

그런 다음 다음을 수행하는 뷰 상태에 대한 사용자 지정 세터가 있습니다.

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

그러나 내가하려는 것은 이것을 허용하는 것입니다.

subview1.tag = FileNotDownloaded | FileDownloaded;

그래서 내 subview1관점의 두 가지 상태로 나타납니다. 현재는 |연산자가 두 개의 열거 형 값을 추가하는 것처럼 보이기 때문에이 두 상태에 표시되지 않습니다 .

그렇게하는 방법이 있습니까?


당신 (subview.tag == viewStatus)은 나에게 잘못된 것 같습니다. ((subview.tag & viewStatus) != 0x0)정확히 일치하는지 확인하지 않으려면 이어야 합니다. 어떤 경우에는 처음에 비트 마스크가 필요하지 않고 평범한 오래된 열거 형 만 필요합니다. 내 대답의 후반부를 참조하십시오.
Regexident

답변:


279

비트 마스크 선언 :

또는 절대 값을 할당에 ( 1, 2, 4, ...) 당신은 선언 할 수 있습니다 비트 마스크 같은를 (이 호출하는 방법) :

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의 답변 참조 )

비트 마스크의 개념은 (일반적으로) 단일 비트 세트로 각 열거 형 값을 정의하는 것입니다.

따라서 OR두 값은 다음을 수행합니다.

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

다음과 동일합니다.

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

비트 마스크 비교 :

비트 마스크를 검사 할 때 명심해야 할 사항 :

정확한 동등성 확인 :

상태가 다음과 같이 초기화되었다고 가정합니다.

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

status 같은지 확인하려면 FileNotDownloaded다음을 사용할 수 있습니다.

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"-표현이 잘못된 이유)?


@Abizern : 감사합니다! 이 질문은 이전에 제공된 것보다 조금 더 설명 할 가치가 있다고 생각했습니다.
Regexident

예,하지만 이진 값을 16 진수 값 (앞에 0x)으로 포맷하고 있습니다. 비트 마스크는 비트 수준에서 작동합니다. 간단한 실수, 당신이 그것을 알아 차리지 못했을 것입니다. 그러나 누군가는 그것을보고 실제로 최대 32 개의 개별 옵션을 가질 수있는 경우 열거 형당 최대 8 개의 옵션을 가질 수 있다고 잘못 가정 할 수 있습니다. 수정 : FileNotDownloaded = (0x1 << 0), // => %...00000001기타
Michael Zimmerman

1
Apple은 enum 및 비트 마스크 선언을 위해 멋진 매크로 쌍 NS_ENUM 및 NS_OPTION을 제공합니다. 그것을 써. 좋은 설명은 NSHipster 사이트를 참조하십시오.
uchuugaka 2013

2
그것들을 완전히 알고 있습니다. ;) (Abizern의 답변 참조) 어쨌든 NS_OPTIONS완전성을 위해 변형을 추가했습니다 .
Regexident

1
권리. 나는 당신이 오버플로에 대해 무엇을 의미하는지 봅니다. 아마도 단순히 ((status & FileNotDownloaded) == FileNotDownloaded) 여야하므로 태그는 두 가지 결과 만 가능합니다.
uchuugaka

20

@Regexident가 훌륭한 대답을 제공했지만 다음과 NS_OPTIONS같이 열거 형 옵션을 선언하는 현대적인 Objective-C 방식을 언급해야합니다 .

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

추가 참조 :


예, NS_ENUM 및 NS_OPTION 매크로는 훌륭합니다.
uchuugaka 2013

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

이렇게하면 비트 OR 및 AND를 효과적으로 수행 할 수 있습니다.


4
값을 정의하는 표준 방법은 1 << 0, 1 << 1, 1 << 2등이 당신이 비트와 마스크로 작업을 취소합니다.
Mike Weller

1
@AhmedAlHafoudh :이 기사는 OP의 두 번째 문제인 비트 마스크 작업 (단순히 선언하는 것과 비교)을 다루지 않습니다. 내 대답을 참조하십시오.
Regexident

1

가독성을 높이기 위해 비트 마스크 검사에 사용할 수있는 유용한 기능입니다.

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

더 엄격한 (bitmask & contains) == contains- 그것은 0으로도 작동합니다contains
DJm00n
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.