Ответ 1
Чтобы сделать это, вы хотите поразрядное И значение, которое вы тестируете против маски, а затем посмотрите, равен ли результат ANDing самой маске:
if ((options & kCFCalendarUnitYear) == kCFCalendarUnitYear) {
// do whatever
}
Например, этот метод из NSCalendar принимает битмаску:
- (NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts
Таким образом, параметры могут быть такими:
NSUInteger options = kCFCalendarUnitYear;
или как:
NSUInteger options = kCFCalendarUnitYear | kCFCalendarUnitMonth | kCFCalendarUnitDay;
То, что я не понимаю, как это делается? Я имею в виду: как они могут вытащить те значения, которые объединены в options
? Если бы я хотел запрограммировать что-то вроде этого, это может принять битмаску, как бы это выглядело?
Чтобы сделать это, вы хотите поразрядное И значение, которое вы тестируете против маски, а затем посмотрите, равен ли результат ANDing самой маске:
if ((options & kCFCalendarUnitYear) == kCFCalendarUnitYear) {
// do whatever
}
Битмаски на самом деле довольно простые. Вы можете думать об этом так (С#, пока кто-то не сможет конвертировать):
public enum CalendarUnits
{
kCFCalendarUnitDay = 1, // 001 in binary
kCFCalendarUnitMonth = 2, // 010 in binary
kCFCalendarUnitYear = 4, // 100 in binary
}
Затем вы можете использовать побитовые операторы для объединения значений:
// The following code will do the following
// 001 or 100 = 101
// So the value of options should be 5
NSUInteger options = kCFCalendarUnitDay | kCFCalendarUnitYear;
Этот метод также часто используется в подпрограммах безопасности:
public enum Priveledges
{
User = 1,
SuperUser = 2,
Admin = 4
}
// SuperUsers and Admins can Modify
// So this is set to 6 (110 binary)
public int modifySecurityLevel = SuperUser | Admin;
Затем, чтобы проверить уровень безопасности, вы можете использовать побитовое и посмотреть, есть ли у вас достаточное разрешение:
public int userLevel = 1;
public int adminLevel = 4;
// 001 and 110 = 000 so this user doesn't have security
if(modifySecurityLevel & userLevel == userLevel)
// but 100 and 110 = 100 so this user does
if(modifySecurityLevel & adminLevel == adminLevel)
// Allow the action
Битмаксы работают, потому что в двоичной форме каждая степень 2 (т.е. 2 0= 1, 2 1= 2, 2 1= 4) занимает одно место в последовательности бит. Например:
decimal | binary
1 | 0001
2 | 0010
4 | 0100
8 | 1000
Когда вы or
(оператор |
в C-подобных языках) два числа a
и b
вместе в c
, вы говорите: "Возьмите биты, которые находятся в a
, b
, или оба, и поместите их в c
." Поскольку степень двух символов представляет собой одну позицию в двоичной строке, нет совпадений, и вы можете определить, какие из них были установлены. Например, если мы or
2 и 4
0010 | 0100 = 0110
Обратите внимание, как это в основном объединяло два. С другой стороны, если мы or
5 и 3:
decimal | binary
5 | 0101
3 | 0011
0101 | 0011 = 0111
обратите внимание, что мы не можем сказать, какие биты пришли откуда, потому что между двоичным представлением каждого из них было перекрытие.
Это становится более очевидным с еще одним примером. Возьмем числа 1, 2 и 4 (все степени два)
0001 | 0010 | 0100 = 0111
Это тот же результат, что и 5 | 3
! Но так как исходные числа являются степенями двух, мы можем однозначно указать, откуда взялся каждый бит.
Ключ помнит, что каждое из этих значений, которые вы объединяете в "параметры", действительно просто число. Я не уверен, насколько вы знакомы с бинарными, но вы можете думать об этом в десятичной форме и просто добавлять числа, а не их ORING.
Скажем, A = 10, B = 100 и C = 1000
Если вы хотите установить опции = A + B, то параметры будут равны 110. Затем метод, который вы назвали, будет смотреть на "десятки" места для A, "сотни" место для B и "тысячи" место для C. В этом примере есть 1 - это место в сотни и десятки, поэтому метод должен знать, что A и B заданы в параметрах.
Это немного отличается, поскольку компьютеры используют двоичный код не десятичный, но я думаю, что идея очень похожа, а иногда проще думать об этом в знакомой системе нумерации.
typedef NS_OPTIONS(NSUInteger, MyOption)
{
OptionNone = 0,
OptionOne = 1 << 0,
OptionTwo = 1 << 1,
OptionThree = 1 << 2
};
if (givenValue & OptionOne) {
// bit one is selected
}
if (givenValue & OptionTwo) {
// bit two is selected
}
Я нашел Calculator.app полезным в визуализации бит-масок. (Просто выберите "Вид" > "Программист", а затем нажмите кнопку "Показать двоичный файл" ). (Вы можете щелкнуть по любой из 0 или 1 в бинарной таблице, чтобы включить или выключить эти биты, или ввести числа в десятичном или шестнадцатеричном формате (используйте переключатель 8 | 10 | 16 NSSegmentedControl для переключения между различными представлениями)).