2010-03-31 9 views
26

Zum Beispiel nimmt diese Methode von NSCalendar eine Bitmaske:Wie funktionieren diese Bitmasken tatsächlich?

- (NSDate *)dateByAddingComponents:(NSDateComponents *)comps toDate:(NSDate *)date options:(NSUInteger)opts 

So können Optionen wie:

NSUInteger options = kCFCalendarUnitYear; 

oder wie:

NSUInteger options = kCFCalendarUnitYear | kCFCalendarUnitMonth | kCFCalendarUnitDay; 

Was ich nicht bekommen ist Wie wird das eigentlich gemacht? Ich meine: Wie können sie die Werte herausziehen, die in options zusammengeführt werden? Wenn ich so etwas programmieren möchte, kann das eine Bitmaske sein, wie würde das aussehen?

+0

die Tags wie iPhone tun und Objective-C wirklich helfen, wenn diese Information wahr ist (und auch die Syntax gleich) in vielen Sprachen? – speedfranklin

Antwort

32

Um dies zu tun, Sie wollen bitweise und der Wert, den Sie die Maske Prüfung sind gegen, dann sehen, ob das Ergebnis der Verknüpfung der Maske gleich selbst:

if ((options & kCFCalendarUnitYear) == kCFCalendarUnitYear) { 
    // do whatever 
} 
+5

== kCFCalendarUnitYear scheint unnötig zu sein – sigjuice

+12

In der Tat 'if (Optionen & kCFCalendarUnitYear)' sollte genug sein, da jeder Wert ungleich Null bedeutet, dass das Bit gesetzt wurde. – FRotthowe

+0

COOL Mann, das ist cool! – dontWatchMyProfile

36

Bitmasken wirklich ziemlich einfach. Sie können wie folgt daran denken (C#, bis jemand konvertieren):

public enum CalendarUnits 
{ 
    kCFCalendarUnitDay = 1, // 001 in binary 
    kCFCalendarUnitMonth = 2, // 010 in binary 
    kCFCalendarUnitYear = 4, // 100 in binary 
} 

Sie können dann die Bit-Operatoren verwenden, um die Werte zu kombinieren:

// The following code will do the following 
// 001 or 100 = 101 
// So the value of options should be 5 
NSUInteger options = kCFCalendarUnitDay | kCFCalendarUnitYear; 

Diese Technik auch oft in Sicherheitsroutinen verwendet wird :

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; 

Dann die Sicherheitsstufe zu überprüfen, können Sie die bitweise verwenden können und sehen, ob Sie ausreichende Berechtigungen:

012.351.
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

Beachten Sie, dass 'if (modifySecurityLevel & userLevel == userLevel) '' if ((modifySecurityLevel & userLevel) == userLevel) sein muss, da sonst der Ausdruck immer als wahr ausgewertet wird. – Drahcir

+0

Sie können auch eine Bitverschiebung wie folgt durchführen: = 1 << 1; – Mark

6

Der Schlüssel ist zu erinnern, dass jeder dieser Werte, die Sie in "Optionen" zusammenführen, wirklich nur eine Zahl ist. Ich bin mir nicht sicher, wie vertraut Sie mit binär sind, aber Sie können sich das im Dezimalsystem vorstellen und einfach Zahlen hinzufügen, anstatt sie zu verknüpfen.

Sagen wir, A = 10, B = 100, und C = 1000

Wenn Sie Optionen = A + B, setzen wollten dann würde Optionen 110 Die Methode gleich Sie an den „Zehner aussehen genannt würde dann "Platz für A, der" Hunderter "Platz für B, und der" Tausender "Platz für C. In diesem Beispiel gibt es eine 1 ist der Hunderter Platz und der Zehner Platz, so dass die Methode wissen würde, dass A und B gesetzt wurden in den Optionen.

Es ist ein wenig anders, da Computer binäre nicht dezimal verwenden, aber ich denke, dass die Idee sehr ähnlich ist, und manchmal ist es einfacher, in einem vertrauten Nummerierungssystem darüber nachzudenken.

+2

gute Erklärung! Vielen Dank! – dontWatchMyProfile

+2

Die Idee ist nicht nur ähnlich, sondern genau gleich. Nur die Basis ist anders: 2 vs. 10. Jeder, der mit der UNIX/Linux-Befehlszeile vertraut ist, hat dies auch in base-8 (oktal) getan, da die numerischen Berechtigungsmasken des chmod-Befehls so funktionieren. –

16

Bitmasken arbeiten, weil im Binär-, jede Potenz von 2 (d.h. 2 0 = 1, 2 1 = 2, 2 = 4) in der Sequenz von Bits einen einzelnen Fleck einnimmt. Zum Beispiel:

decimal | binary 
1  | 0001 
2  | 0010 
4  | 0100 
8  | 1000 

Wenn Sie or (der Betreiber | in C-ähnlichen Sprachen) zwei Zahlen a und b zusammen in c, Sie sagen, „die Bits nehmen, die in a sind, b oder beides und Setzen Sie sie in c."Da eine Zweierpotenz eine einzelne Position in einer binären Zeichenfolge darstellt, gibt es keine Überschneidungen, und Sie können, welche davon wurden eingestellt bestimmen. Zum Beispiel, wenn wir or 2 und 4

0010 | 0100 = 0110 

Beachten Sie, wie es die im Grunde kombiniert . zwei auf der anderen Seite, wenn wir or 5 und 3:.

decimal | binary 
5  | 0101 
3  | 0011 

0101 | 0011 = 0111 

Ankündigung, dass wir keine Möglichkeit zu sagen haben, die Bits kam, von wo aus, weil es eine Überlappung zwischen der binären Darstellung von jeder war

Dies beco mes mehr offensichtlich mit einem weiteren Beispiel. Lassen Sie uns die Zahlen 1 nehmen, 2 und 4 (alle Zweierpotenzen)

0001 | 0010 | 0100 = 0111 

Dies ist das gleiche Ergebnis wie 5 | 3 ist! Aber da die ursprünglichen Zahlen Potenzen von zwei sind, können wir eindeutig sagen, woher jedes Bit kam.

+0

Tolles Beispiel, aber ich verstehe nicht, wie dein letzter Satz. Wie können wir feststellen, ob die 0111 von 0001 | 0010 | 0100 OR 0101 | 0011 stammt? – joels

+0

Der springende Punkt ist, dass wir * a priori * wissen, dass die Flags nur Potenzen von zwei sind. Mit anderen Worten, wir wissen, dass es '0001 | 0010 | 0100 |' und nicht '0101 | 0011 'ist, weil Letzteres einfach keine Option ist, da es nicht nur aus Potenzen von Zwei besteht. – notJim

0

Ich habe Calculator.app als hilfreich bei der Visualisierung von Bitmasken gefunden. (Wählen Sie einfach "Ansicht"> "Programmer" und klicken Sie dann auf "Binary anzeigen"). (Sie können auf eine der 0 oder 1 in der Binär-Tabelle klicken, um diese Bits ein- oder auszuschalten, oder Zahlen in Dezimal oder Hex eingeben (verwenden Sie die 8 | 10 | 16 NSSegmentedControl, um zwischen verschiedenen Darstellungen zu wechseln)).

3
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 
} 

http://en.wikipedia.org/wiki/Mask_(computing)

Verwandte Themen