24.09.2012

NSArray und NSMutableArray

In diesem Artikel werden die Klassen NSArray und NSMutableArray kurz beschrieben. Außerdem wird die Anwendung einiger weniger ausgewählter Funktionen demonstriert. Unter anderem wird erklärt, wie sich ein Array mit einfachen Mitteln sortieren läßt.

NSArray erstellen

Die folgende Funktion zeigt die Verwendung eines NSArray.

void arrayTest() {
	//Declare NSArray
	NSArray* array;

	//Declare NSNumber
	NSNumber* number;
	//Alloc and init NSNumber with 42
	number = [[NSNumber alloc]initWithInt:42];

	//Alloc and init NSArray with a NSNumber and a NSString
	array = [[NSArray alloc]initWithObjects: number, @"Arthur Dent", nil];

	//Print the content of the array
	print(array);

}

Als erstes wird eine Variable array deklariert. Danach wird eine Variable number deklariert, allokiert und mit 42 initialisiert. Dann wird das array allokiert und mit Objekten number und Arthur Dent initialisiert. Abließend wird ein nil übergeben, um das Ende des Arrays zu signalisieren. Mit print werden die Elemente des arrays auf der Konsole ausgegeben.

Ausgabe eines NSArray

Die Funktion print sieht folgendermaßen aus:

void print(NSObject* aCollection) {
	//Declare a NSEnumerator
	NSEnumerator* aEnum;

	//Declare an object
	id object;

	//Get an enumerator
	aEnum = [aCollection objectEnumerator];

	//Iterate while there is a next object
	while( (object = [aEnum nextObject]) ) {
		//Print object
		NSLog(@"%@",object);
	}
}

Die Print-Funktion erzeugt einen Enumerator indem die Nachricht objectEnumerator an die Collection geschickt wird. Da NSArray von NSObject erbt, ist die Parameterübergabe an die print-Funktion richtig. Obwohl die Klasse NSObject keine Funktion objectEnumerator besitzt, kommt die Nachricht bei der Klasse NSArray an.

Der Enumerator wird verwendet, um in der while-Schleife über die Collection zu iterieren. Bei jedem Schleifendurchlauf wird der Wert des Element ausgegeben.

NSMutableArray erstellen

Wie in dem Beispiels zu sehen ist, müssen die Werte innerhalb des Arrays während der Initialisierung übergeben werden. Sie können danach nicht mehr verändert werden. (Die Objekte selbst schon, aber nicht die innerhalb des Arrays.). D.h. es können keine Elemente gelöscht oder hinzugefügt werden. Abhilfe schafft die Klasse NSMutableArray, die im Folgenden erklärt wird.

void arrayMutableTest() {
	//Declare NSMutableArray
	NSMutableArray* array;

	//Allocate and init the NSMutableArray
	array = [[NSMutableArray alloc] init];

	//Declare NSNumber
	NSNumber* number;
	//Alloc and init NSNumber with 42
	number = [[NSNumber alloc]initWithInt:42];

	//Insert a NSNumber at index 0
	[array insertObject:number atIndex:0];

	//Insert a NSString at the end of the array
	[array insertObject:@"Arthur Dent" atIndex:[array count]];

	//Print the content of the array
	print(array);
}

In dieser Methode wird ein NSMutableArray deklariert, allokiert und initialisiert. Dieses Array enthält zu Beginn keine Elemente. Dann wird wieder ein Objekt vom Typ NSNumber erzeugt und an der ersten Position (Index 0) eingefügt. Als nächstes wird ein NSString am Ende eingefügt. Dafür wird die Funktion count des Arrays aufgerufen um den maximalen Index zu bestimmen. Dann wird das Array auf der Konsole ausgegeben. Da NSMutableArray von NSArray erbt, kann die gleiche print-Funktion, wie schon in der Methode arrayTest, verwendet werden.

Die Ausgabe auf der Konsole sieht folgendermaßen aus:

2008-06-10 20:11:32.519 ContainerTest[51835:10b] 42
2008-06-10 20:11:32.522 ContainerTest[51835:10b] Arthur Dent
2008-06-10 20:11:32.522 ContainerTest[51835:10b] 42
2008-06-10 20:11:32.522 ContainerTest[51835:10b] Arthur Dent

Sortieren eines NSMutableArray

Um das Sortieren etwas spannender zu machen, erstellen wir eine Klasse Person mit den Properties personname, personfirstname und personbirthday. So haben wir später die Möglichkeit das NSArray nach jedem dieser Properties zu sortieren.

Die Header-Datei der Person sieht folgendermaßen aus:

//
//  Person.h
//  NSArraySortieren
//
//  Created by Jörn Hameister on 24.09.12.
//  Copyright 2012 http://www.hameister.de . All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Person : NSObject {
}

@property (assign, nonatomic) NSString* personname;
@property (assign, nonatomic) NSString* personfirstname;
@property (assign, nonatomic) NSDate* personbirthdate;

@end

Die Implementierung der Klasse ist auch nicht sehr kompliziert:

//
//  Person.m
//  NSArraySortieren
//
//  Created by Jörn Hameister on 24.09.12.
//  Copyright 2012 http://www.hameister.de . All rights reserved.
//

#import "Person.h"

@implementation Person
@synthesize personname = _personname;
@synthesize personfirstname = _personfirstname;
@synthesize personbirthdate = _personbirthday;

-(NSString*) description {
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"dd.MM.yyyy"];
    return [[NSString alloc] initWithFormat:@"%@ %@ %@", _personfirstname, _personname,
                     [dateFormatter stringFromDate:_personbirthday]];
}

@end

Die Methode description wurde überladen, damit wir eine formatierte Ausgabe erhalten. Weitere Informationen zum NSDateFormatter findet man hier: Datum und Zeit.

Als nächstes legen wir uns ein NSMutableArray mit ein paar Person an:

NSMutableArray* persons = [[NSMutableArray alloc]init];

NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"dd.MM.yyyy"];

Person *person1 = [[Person alloc]init];
person1.personfirstname = @"Hugo";
person1.personname = @"Schwidnitzer";
person1.personbirthdate = [dateFormatter dateFromString:@"01.01.1970"];

Person *person2 = [[Person alloc]init];
person2.personfirstname = @"Donald";
person2.personname = @"Duck";
person2.personbirthdate = [dateFormatter dateFromString:@"20.02.1974"];

Person *person3 = [[Person alloc]init];
person3.personfirstname = @"Bart";
person3.personname = @"Simpson";
person3.personbirthdate = [dateFormatter dateFromString:@"24.06.1950"];

[persons addObject:person1];
[persons addObject:person2];
[persons addObject:person3];

NSLog(@"Unsortierte Personen: %@", persons);

Zum Sortieren nach dem Vornamen kann folgender Codeschnipsel verwendet werden:

NSSortDescriptor* sortDescriptor =
             [[NSSortDescriptor alloc] initWithKey:@"personfirstname" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedPersons = [persons sortedArrayUsingDescriptors:sortDescriptors];
NSLog(@"%@", sortedPersons);

Es ist anzumerken, dass der Aufruf eigentlich ein Einzeiler ist. Zu Verständnis ist die verhergehende Variante allerdings besser geeignet:

//Sort the NSArray with personfirstname
NSArray *sortedPersons =
          [persons sortedArrayUsingDescriptors:
               [NSArray arrayWithObject:[[NSSortDescriptor alloc] initWithKey:@"personfirstname" ascending:YES]]
          ];
NSLog(@"Nach Vornamen sortiert: %@", sortedPersons);

Soll nun nach dem Geburtsdate sortiert werden, ist folgende Anpassung notwendig:

NSSortDescriptor* sortDescriptor =
             [[NSSortDescriptor alloc] initWithKey:@"personbirthdate" ascending:YES];
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *sortedPersons = [persons sortedArrayUsingDescriptors:sortDescriptors];
NSLog(@"Nach Geburtsdatum sortiert: %@", sortedPersons);

Als Ausgabe auf der Konsole erhält man folgende Werte: (unsortiert, nach Vornamen sortiert, nach Geburtsdatum sortiert)

2012-09-24 14:07:06.354 NSArraySortieren[1229:903] Unsortierte Personen: (
    "Hugo Schwidnitzer 01.01.1970",
    "Donald Duck 20.02.1974",
    "Bart Simpson 24.06.1950"
)
2012-09-24 14:07:06.357 NSArraySortieren[1229:903] Nach Vornamen sortiert: (
    "Bart Simpson 24.06.1950",
    "Donald Duck 20.02.1974",
    "Hugo Schwidnitzer 01.01.1970"
)
2012-09-24 14:07:06.359 NSArraySortieren[1229:903] Nach Geburtsdatum sortiert: (
    "Bart Simpson 24.06.1950",
    "Hugo Schwidnitzer 01.01.1970",
    "Donald Duck 20.02.1974"
)

Eine weitere Möglichkeit ein NSArray zu sortieren, sind Blocks, die seit 10.6 verfügbar sind. Der folgende Code-Schnipsel zeigt ein Beispiel zum Sortieren nach dem Vornamen:

NSArray* sortedPersons = [persons sortedArrayUsingComparator:^NSComparisonResult(Person* p1, Person* p2) {
    return [[p1 personfirstname] compare:[p2 personfirstname]];
}];
NSLog(@"Nach Vornamen sortiert: %@", sortedPersons);

Das Beispiel kann leicht so angepasst werden, dass auch ein Sortieren nach Geburtstag oder Nachname möglich ist.

History

10.06.2008: Erstellt.

12.01.2011: Kleine Korrekturen.

24.09.2012: Sortieren von NSArrays hinzugefügt.