Programmieren mit Swift - Für macOS und iOS
Programmieren mit Swift - Für macOS und iOS
NSNumber

Eine Auflistung nur aus Zahlen zu erstellten gestaltet sich schwierig, da einfache C-Datentypen wie float, int oder double einem NSArray oder NSMutableArray nicht hinzugefügt werden können. Sie sind keine Objekttypen und haben demzufolge auch keinen Zeiger, den ein Array als Verweis verwenden könnte.
Abhilfe für dieses Problem schaffen spezielle Klassen aus dem Foundation Framework, wie zum Beispiel NSNumber, eine Wrapper-Klasse, die speziell für Zahlen konzipiert wurde.
Im praktischen Gebrauch erweist sich NSNumber als besonders vielseitig, funktioniert diese Klasse doch als Container für vielerlei primitive Datentypen wie int, float, double und sogar bool.
double myDouble = 12.14;
NSNumber *myNumber = [[NSNumber alloc] initWithDouble:myDouble];
NSLog(@"Number: %@",myNumber);
Besonderes Augenmerk sollte man hier auf den Format Specifier legen. Die gespeicherte Zahl ist jetzt ein Objekt und muss durch %@ ausgegeben werden. Was aber wird in diesem Bezeichner gespeichert? Ist NSNumber doch nur ein Speicherzeiger auf den tatsächlichen double Wert? Wäre dies so, könnte sich der double-Wert verändern, wenn das Objekt verändert wird. Zu dieser Ansicht könnte man vielleicht kommen. Ein paar Zeilen Programmcode liefern Gewissheit, was tatsächlich geschieht.
double myDouble = 12.14;
NSNumber *myNumber = [[NSNumber alloc] initWithDouble:myDouble];
NSLog(@"Number: %@",myNumber);

myNumber = [
NSNumber numberWithDouble:55.44];

NSLog(@"Number: %@",myNumber);
NSLog(@"double: %f",myDouble);
Natürlich gibt es keine Wechselwirkung mit der double-Variablen. Wurde NSNumber mit einem Wert initialisiert, wird es zu einem selbstständigen Objekt, welches einen eigenen Wert verwaltet. Auch die alternative, verkürzte Schreibwiese macht da keinen Unterschied.
NSNumber *myNumber = [NSNumber numberWithDouble:myDouble];
Diese Schreibweise nennt man auch Convenience Allocator. Die Anweisung ist nicht nur leichter zu lesen, zusätzlich wird das NSNumber-Objekt dem aktuellen Autorelease-Pool hinzugefügt. Ein explizites release des Objektes, wie es bei der Verwendung von initWithDouble erforderlich wird, ist nicht mehr nötig.

Wie das Beispiel bewies, gibt es keine permanente Verbindung zwischen NSNumber und dem ursprünglichen double-Wert. Wie aber verhält es sich, wenn NSNumber von einem Array verwaltet wird? Da es sich um einen Objekttyp handelt, kann myNumber einem NSArray oder einem NSMutableArray problemlos hinzugefügt werden. Wie mehrfach erwähnt würde das mit dem double-Wert nicht funktionieren.
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSNumber *myNumber = [NSNumber numberWithDouble:752.65];
[myArray
addObject:myNumber];

myNumber = [
NSNumber numberWithDouble:55.44];

NSLog(@"Number im Array: %@",[myArray objectAtIndex:0]);
NSLog(@"Number: %@",myNumber);
Auch in diesem Fall beeinflusst die Änderung von myNumber nicht das Objekt im Array. Die Erklärung für dieses Verhalten ist denkbar einfach. NSNumber ist immutable, das heisst nicht änderbar. Was scheinbar nach Überschreiben des bestehenden Wertes aussieht, ist es in Wirklichkeit nicht. Bei einer erneuten Zuweisung wird ein neues Objekt mit eigenem Speicherplatz erzeugt, während das Array noch auf den alten Speicherplatz verweist und daher den ursprünglichen Wert beinhaltet. Ein einfaches Überschreiben des NSNumber Wertes ist also nicht möglich, es wird immer wieder ein eigenständiges Objekt erzeugt. Auch wenn sich ein NSNumber Objekt in einem Array befindet, kann auf diesem Weg kein Wert geändert werden. Allerdings ist es möglich, ein Array Element auszutauschen. Dafür muss man aber wissen, an welcher Position im Array sich das gewünschte Objekt befindet. Den selben Variablennamen wie zuvor zu verwenden, ist hingegen problemlos möglich.
NSMutableArray *myArray = [[NSMutableArray alloc] init];
NSNumber *myNumber = [NSNumber numberWithDouble:752.65];
[myArray
addObject:myNumber];

NSLog(@"Number im Array: %@",[myArray objectAtIndex:0]);
myNumber = [
NSNumber numberWithDouble:975.92];

[myArray replaceObjectAtIndex:
0 withObject:myNumber];
NSLog(@"Number im Array: %@",[myArray objectAtIndex:0]);
Beim Vergleich zweier Variablen vom Typ NSNumber ist besondere Vorsicht nötig. Eine einfache „ist gleich“ Abfrage würde abfragen, ob es das gleiche Objekt ist, also die gleiche Speicheradresse hat, nicht ob der Wert identisch ist. Da man in den meisten Fällen aber den Zahlenwert vergleichen will, muss man sich der Methode isEqualToNumber bedienen.
NSNumber *number1 = [[NSNumber alloc] initWithInt:5];
NSNumber *number2 = [[NSNumber alloc] initWithInt:2];

if ([number1 isEqualToNumber:number2])
{
    NSLog(@"Werte sind gleich.");
}
else
{
    NSLog(@"Werte sind ungleich.");
}
Als erweiterte Alternative kann auch die compare-Methode verwendet werden. Mit ihr ist es sogar möglich zu ermitteln, welcher der zu vergleichenden Werte größer und welcher kleiner ist.
NSNumber *wert1 = [NSNumber numberWithInt:5];
NSNumber *wert2 = [NSNumber numberWithInt:5];

switch ([wert1 compare:wert2])
{
    case NSOrderedAscending:
        NSLog
(@"Wert 1 ist kleiner als Wert 2"); 
        break
;

   
case NSOrderedSame:
        NSLog(@"Wert1 und Wert2 sind gleich.");
        break;

    case NSOrderedDescending:
        NSLog
(@"Wert 1 ist größer als Wert 2");
        break
;
    default
:
        NSLog
(@"default, sollte nicht passieren");
}
Anmerkung: Der default-Fall sollte in diesem Beispiel nicht eintreten, da alle anderen möglichen Fälle abgedeckt sind.
Auch als Container für boolsche Werte funktioniert die Klasse NSNumber nicht viel anders und benötigt lediglich eine andere Methode zur Initialisierung.
NSNumber *myBoolNumber =[NSNumber numberWithBool:YES];

if ([myBoolNumber boolValue])
{
    NSLog(@"Ja");
}
else
{
    NSLog
(@"Nein");
}