Der, die oder das Array?
Das ist hier nicht die Frage. Nicht nur weil es nicht wichtig ist wie man es ausspricht. Wichtig ist jedoch der Unterschied zwischen “normalen” und assoziativen Arrays.
Zitat von Wikipedia:
Statt von einem assoziativen Array spricht man auch von einem Dictionary (Smalltalk, Python, Objective-C, PostScript, C#), einer Map (C++, Java), einem Hash (Perl, Ruby) oder einer Hashtable/Hashmap (Java, Windows PowerShell).
Das NSDictionary bietet hier die Möglichkeiten eines assoziativen Arrays, welches jedoch nicht weiter erläutert wird. (Evtl. in einem späterem Posting)
NSArray
Factory Methoden
Factory-Methoden sind Methoden, die statisch aufgerufen werden und eine Instanz (Objekt) der zugehörigen Klasse (hier NSArray) zurück geben. Häufig verwendete Factory Methoden sind zB.:
| + (id)array | Erstellt ein leeres Array und gibt es zurück. |
| + (id)arrayWithArray:(NSArray *)anArray | Erstellt ein Array, welches Objekte des gegebenen Arrays beinhaltet und gibt es zurück. |
| + (id)arrayWithContentsOfFile:(NSString *)aPath | Erstellt ein Array, welches aus der Datei vom gegebenem Pfad Inhalte ausliest. Die angegebene Datei muss hier vom Typ .plist sein um die Methode nutzen zu können. |
| + (id)arrayWithContentsOfURL:(NSURL *)aURL | Ähnliche Methode zu arrayWithContentsOfFile mit der Ausnahme, dass die .plist-Datei von einem Remoteserver geladen werden kann. Die Methode kann genutzt werden um das Array als Ergebnis eines Webservice-Aufrufes zu erzeugen. |
| + (id)arrayWithObject:(id)anObject | Erstellt ein Array mit ausschließlich dem gegebenem Objekt und gibt es zurück. |
| + (id)arrayWithObjects:(id)firstObj, … | Eine erweiterte Methode zu arrayWithObject. Hier können mehrere Objekte gleichzeitig dem Array hinzugefügt werden. Wichtig ist hier, dass das letzte “Objekt” vom Typ nil ist, da die Methode sonst nicht funktioniert. |
| + (id)arrayWithObjects:(const id *)objects count:(NSUInteger)count | Erstellt ein Array, welches die gegebene Anzahl an Objekten eines C Arrays beinhaltet und fügt dieses Array dem Array hinzu. |
Nachfolgend ein paar Beispiele:
// Erstellen eines NSArray's mit einem Objekt vom Typ NSString. NSArray *myArray = [NSArray arrayWithObject:@"foo"]; // Erstellt ein NSArray mit mehreren Objekten. Nicht zu vergessen: Das letzte Objekt als nil deklarieren! NSArray *myArray2 = [NSArray arrayWithObjects:@"foo", @"bar", @"baz", nil]; // Erstellen eines NSArray's mit einem anderen Array. NSArray *myArray3 = [NSArray arrayWithArray:myArray2]; // Erstellt ein NSArray mit Daten von renepardon.de. NSArray *myArray4 = [NSArray arrayWithContentsOfURL:[NSURL URLWithString:@"http://renepardon.de/uploads/2010/07/foo.plist"]];
Anstatt die Factory-Methoden zu nutzen kann man natürlich auch ein NSArray-Objekt per “Hand” initialisieren. Dies macht man wie folgt:
NSArray *foo = [[NSArray alloc] initWithObjects:@"foo",@"bar",@"baz",nil];
Man beachte den * vor foo. NSArray ist kein primitiver Datentyp, daher wird der * benötigt. Wenn wir nicht die statischen Methoden nutzen, müssen wir uns selber um die Speicherverwaltung kümmern. In diesem Fall ist es also nötig Speicher zu reservieren (alloc) – kommt von allocate – und dann das Objekt danach zu erstellen und in foo zu speichern.
Zugriff auf NSArray’s
Nachfolgend erhaltet ihr eine Übersicht der wichtigsten Zugriffsmethoden eines NSArray’s.
| - (BOOL)containsObject:(id)anObject | Gibt einen boolischen Wert (true/false) zurück wenn das gegebene Objekt existiert oder nicht. |
| - (NSUInteger)count | Gibt eine Ganzzahl mit der Anzahl der Objekte zurück. (Die Größe des Arrays) |
| - (id)lastObject | Gibt das letzte Objekt (mit größtem Index, jedoch nicht das nil-Objekt!) des Arrays zurück. |
| - (id)objectAtIndex:(NSUInteger)index | Das gewünschte Objekt wird zurück gegeben. |
Array’s durchsuchen
Es gibt nur eine Möglichkeit den Index eines zugehörigen Objektes zu erhalten/finden: indexOfObject.
NSString *f = @"foo"; NSString *b = @"bar"; NSString *z = @"baz"; NSArray *myArray2 = [NSArray arrayWithObjects:f,b,z,nil]; NSInteger idx = [myArray2 indexOfObject:b]; // Gibt 1 zurück (Die Indexierung beginnt bei 0)
Nachrichten an Objekte im Array senden
Soweit sogut. Sagen wir, ihr habt ein Array (bullets) mit Objekten (bullet), welche etwas machen können (z.B. sich bewegen). Nun möchten wir die Kugeln (bullet) einen Pixel vorwärts rollen lassen. Schneller, als alle Kugeln (bullets-Array) durch eine Schleife laufen zu lassen und jedesmal [bullet move] aufzurufen, ist es mit einem einzigen Methoden-Aufruf Cocoa die ganze Arbeit machen zu lassen. Ja, so etwas ist tatsächlich möglich. In Cocoa wird die entsprechende Methode makeObjectsPerformSelector genannt.
Nachfolgend seht ihr ein kleines Beispiel wie diese Methode funktioniert. Der Aufruf der Methode move der bullet-Objekte wird nun für jede Kugel aufgerufen. Das ist die sauberste und einfachste Variante eine Methode für alle Objekte des Arrays ausführen zu lassen.
[bullets makeObjectsPerformSelector:@selector(move)];
Wenn jetzt jedoch noch ein Argument für den Methodenaufruf erwartet wird, so könnte der Aufruf mit der nächsten Methode gelöst werden:
– (void)makeObjectsPerformSelector:(SEL)aSelector withObject:(id)anObject
Sortieren von Arrays
Es gibt viele Wege die nach Bagdad führen, aufzeigen tu ich jedoch nur einen. (Der am meisten Sinn macht)
// Die Funktion wird ein Array wie folgt zurück geben: [@"bar",@"baz",@"foo"] NSArray *sortedArray = [myArray2 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
Es können verschiedenste String-Vergleichsfunktionen übergeben werden. Die Vergleichsmethode kann genausogut auch überschrieben werden. Wichtig bei einem @selector-Aufruf ist, dass hinter dem Selector ein Doppelpunkt steht!
Arrays durchlaufen (Schleifen)
Wie in jeder anständigen Programmier- oder auch Scriptsprache, gibt es auch in Objective-C Schleifen. Die am häufigsten gebrauchte Schleife hier ist die for-Schleife, deren Anwendung ich im nächsten Beispiel zeigen möchte:
for(NSString *myStr in myArray2) {
NSLog(myStr);
}
Dieses Beispiel durchläuft myArray2 und gibt jedes Element vom Typ String in der Konsole aus.
Arrays für die spätere Verwendung (zwischen)speichern
Es kann nötig sein das aktuelle Array zu speichern um es später erneut verwenden zu können. Wie bereits zu Beginn erwähnt, ist es möglich ein Array als Datei zu speichern (.plist) und dieses Datei als Resource für das neu zu initialisierende Array zu wählen.
Wir können also unser aktuelles Array wie folgt erstellen und in filePath speichern:
NSArray *myArray2 = [NSArray arrayWithObjects:@"foo",@"bar",@"baz",nil]; [myArray2 writeToFile:filePath atomically:YES];
Warum hier atomically YES? Dafür habe ich folgendes Beispiel-Szenario zur Hand:
You want to write a huge array to disk to save it for later. When your app starts it checks the disk to see if this file exists, if it does it loads an NSArray from it. If it doesn’t it creates a new NSArray. Say the last time the app ran, the system crashed while the file was being written. If atomically was set to NO, the original file would be corrupt and now the application would be loading corrupt data every time it starts from now on (most likely causing a crash). However, if you set atomically to YES, the temp file would get corrupted and the app would never see it. That way, the next time the app starts it will create a new fresh NSArray and all will be good.
NSMutableArray
Methoden
Ein NSMutableArray ist die Ableitung von NSArray. Es ist veränderbar, jedoch kein assoziatives Array!
Zunächst ein paar verfügbare Methoden:
| addObject: | Fügt das gegebene Objekt an das Ende des Arrays an. |
| insertObject:atIndex | Fügt das gegebene Objekt an der stelle des gewünschten Indexes ein. Die Indexe der übrigen Objekte wird automatisch angepasst. |
| removeObject: | Entfernt alle Instanzen eines Objektes im Array. |
| removeObjectAtIndex: | Löscht ein Objekt am Index. |
| replaceObjectAtIndex:withObject: | Ersetzt ein Objekt am Index mit dem gegebenem. Gibt einen Fehler zurück wenn die OutOfBounds-Exception geworfen wurde |
| sortUsingSelector: | Sortiert ein Array. Siehe: SortUsingSelector |
| removeObjectIdenticalTo | Prüft ob ein Objekt vorhanden ist befor es gelöscht wird. Für ein Beispiel kann in der Apple-Doku nach NSMutableArrayRemoveObjectIdenticalTo gesucht werden. |
Beachtet, dass das Array selber keine KeyValueObserving Benachrichtigungen verschickt wenn die oben beschriebenen Methoden aufgerufen werden. Wenn eine eurer Klassen ein Array ändert, so muss die entsprechende Klasse die Methode willChange:valuesAtIndexes:forKey, etc selber aufrufen – wenn benötigt.
Nun soll es jedoch nicht an den Beispielen scheitern
// Erstellt ein einfaches "mutable array". NSMutableArray *array; // Initialisiert ein "mutable array", nachdem Speicher reserviert wurde. NSMutableArray *array = [[NSMutableArray alloc] init]; // Zählt alle Objekte des Arrays array und speichert das Ergebnis in der Variable arrayCount. int arrayCount = [array count]; // Hängt '15' an das "mutable array" an. [array addObject:[NSNumber numberWithInt:15]]; // Gibt das 379te Objekt des Arrays zurück und speichert es in arrayVariable. id arrayVariable = [array objectAtIndex:378];
Iterieren von Array’s
Um durch ein Array zu iterieren könnte man im Gegensatz zur obigen for-Schleife auch eine while-Schleife nutzen. Zusätzlich hängt im nachfolgenden Beispiel noch ein Iterator dran:
NSEnumerator *enumerator = [myArray objectEnumerator];
id element;
while(element = [enumerator nextObject])
{
NSLog(element);
}
Möchte man jetzt noch einen Schritt weiter gehen, so könnte man auch mit Code-Blöcken arbeiten. Die obige while-Schleife würde dann wie folgt aussehen:
// Deklaration des Blocks: -(void)do:(OCBlock *)aBlock. // Blockaufruf: [myArray do:ocblock(:each | [self doMyThingWith:each];)
Zusammenfassung
NSMutableArray ist eine Ableitung (subclass) von NSArray und beinhaltet somit alle Methoden von NSArray. Doch was kann ich einem “mutable array” hinzufügen? Alles was vom Typ NSObject ist. Und was ist nun der Vorteil/Nachteil von NSMutableArray? Immerhin kann NSMutableArray nur NSObject-Objekte und Zeiger auf solche als Objekte aufnehmen. Na gut, ich denk jetzt ist Kreativität eurerseits gefragt