0

I am reading documentation to NSCalendar and for curiosity i look deeper into CFCalendarUnit and i saw this:

typedef enum {
   kCFCalendarUnitEra = (1 << 1),
   kCFCalendarUnitYear = (1 << 2),
   kCFCalendarUnitMonth = (1 << 3),
   kCFCalendarUnitDay = (1 << 4),
   kCFCalendarUnitHour = (1 << 5),
   kCFCalendarUnitMinute = (1 << 6),
   kCFCalendarUnitSecond = (1 << 7),
   kCFCalendarUnitWeek = (1 << 8),
   kCFCalendarUnitWeekday = (1 << 9),
   kCFCalendarUnitWeekdayOrdinal = (1 << 10),
   kCFCalendarUnitQuarter = (1UL << 11),
   kCFCalendarUnitWeekOfMonth = (1UL << 12),
   kCFCalendarUnitWeekOfYear = (1UL << 13),
   kCFCalendarUnitYearForWeekOfYear = (1UL << 14),
} CFCalendarUnit;

I'm using this like:

NSUInteger preservedComponents = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit;

And it return 124

So I try to do this:

NSUInteger preservedComponents = NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit;

And i get 30.

I can't figure it out. How it works?

Jakub
  • 13,712
  • 17
  • 82
  • 139
  • 2+3+8+16 = 30. 2 + 4 + 8 + 16 + 32 + 64 = 124. What exactly was your question? Naturally the bitwise OR operand just happens to be equivalent to + because there is always exactly one and unique bit set in each operand. – Hermann Klecker Aug 02 '13 at 15:30
  • Yes, before you plenty of people answer below. And just to be clear... 2+3+8+16 is NOT 30... 2+4+8+16 is. – Jakub Aug 02 '13 at 20:55
  • Yes of course, I meant to write 2+4+8... – Hermann Klecker Aug 05 '13 at 08:31

4 Answers4

5

These are just binary numbers. 1 << n is a binary number with 1 in the n-th position and zeros everywhere else. To figure out a value of several of them OR-ed together, write a binary number with ones in the positions corresponding to how many positions was 1 shifted in their definition, and convert that number to decimal representation.

For example,

NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit

has ones in positions 1 (era), 2 (year), 3 (month) and 4 (day), and zeros in all remaining positions; positions are numbered from zero starting on the right. It looks like this:

Position:  76543210
           --------
Bit value: 00011110

This 00011110 in binary representation is 30 in decimal representation.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
3

The enum is using a bitwise shift operation (wiki) to produce values which each set only one bit in the 'int' used to store to enum value. By doing this you can OR (bitwise operation) the values together and still be able to tell which options are set.

Viewing the preservedComponents as an actual number does mean something, but it isn't immediately obvious because what it means is a set of selected bits in a specified format / mask.

Wain
  • 118,658
  • 15
  • 128
  • 151
1

when you write (1 << k) you obtain that only the k-th (starting from the right, 0 based) bit is turned on. If you write (1 << a) | (1 << b) you obtain that only a-th and b-th bit are set.

When you obtain 124, for example, you are dealing with the binary number 1111100. This means you combined together (OR operator) the numbers this way

(1 << 2) | (1 << 3) | (1 << 4) | (1 << 5) | (i << 6)

Idon't know what this does mean in terms of your symbolic names, as it appears you copied the wrong enum. But I'm sure you got the point! :)

Stefano Falasca
  • 8,837
  • 2
  • 18
  • 24
1

| is a bitwise OR operator. It takes two bit patterns of equal length and performs the logical inclusive OR operation on each pair of corresponding bits. So speaking shortly it takes NSYearCalendarUnit, NSMonthCalendarUnit, etc. and performs an OR operation which results in your 124 and 30. This is very common way of passing combination of flags as arguments.

tomi.lee.jones
  • 1,563
  • 1
  • 15
  • 22