Hallo Zusammen,
bei fast allen bisher von mir programmierten Apps war es notwendig Daten aus einer Property List (auch plist genannt) auszulesen. Eine pList kann über File ➸ New ➸ File… ➸ Ressource ➸ Property List dem Projekt hinzugefügt und direkt in XCode bearbeitet werden. Hier mal ein Beispiel:
In diesem Beitrag erkläre ich wofür man eine pList benötigt und wie man mit ihr arbeitet.
Eine plist ist ein xml Dokument mit einer spezielle definierten Datenstruktur. Dabei legt man für einen Bezeichner den Datentyp und den Inhalt fest.
Property Listen sind ein tolles Hilfsmittel um einer App Konfigurationen hinzuzufügen oder den Aufbau verschiedener Level zu definieren. So könnte das Grundgerüst eines Levels in der Klasse definiert sein und die konkrete Platzierung der Gegenstände in den Level aus der plist kommen. Auf diese Weise benötigt man nur eine Klasse anstatt einer pro Level. Ein weiterer Vorteil ist, dass Property Listen unabhängig von der App bearbeitet werden können. So kann der Entwickler programmieren und ein Leveldesigner parallel an einem anderen Rechner die plist schreiben.
Kommen wir nun zum Quellcode. Das root Element einer pList ist immer eine NSDictionary – daher definieren wir uns eine globe Dictionary Variable im Header:
NSDictionary *_rootDictionary;
In unserer Klasse defnieren wir eine Methode getDictionaryFromPlist.
-(NSDictionary *)getDictionaryFromPlist:(NSString *)fileName { return (NSDictionary *)[self readPlist:fileName]; }
Als Parameter benötigt die Methode den Dateinamen der pList als String. Sie liefert anschließend ein Object vom Typ NSDictionary zurück – also unsere pList. Allerdings wird die eigentliche Arbeit nicht in dieser Methode getan – statt dessen rufen wir eine Methode readPlist auf, welcher wir ebenfalls den Dateinamen übergeben. Wir kapseln die eigentliche Methode um nicht bei jedem Aufrug den Typecast (NSDictionary *) durchführen zu müssen.
-(id)readPlist:(NSString *)fileName { NSData *plistData; NSString *error; NSPropertyListFormat format; id plist; NSString *localizedPath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"plist"]; plistData = [NSData dataWithContentsOfFile:localizedPath]; plist = [NSPropertyListSerialization propertyListFromData:plistData mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&error]; if (!plist) { NSLog(@"Error reading plist from file '%s', error = '%s' ", [localizedPath UTF8String], [error UTF8String]); [error release]; } return plist; }
In readPlist definieren wir uns zunächst einige Hilfsvariabeln. Der zu übergebene Parameter fileName darf nicht die Endung .plist haben, da sie durch die Methode pathForResource hinzugefügt wird. Zunächst wird der Inhalt der hoffentlich gefundenen Datei in ein NSData Object gefüllt. Anschließend wird das NSData Object durch die propertyListFromData Methode als pList interpretiert. Die so gewonnene pList wird als Rückgabewert durch return plist; übergeben.
Wir können uns nun jeder Zeit den Inhalt einer pList in unsere NSDictionary Variable laden. Meine pList heißt Parameter.plist
_rootDictionary = [self getDictionaryFromPlist:@"Parameter"];
Da wir nun ein Dictionary Objekt haben können wir auf jedes Element der pList über dessen Bezeichner zurückgreifen. Selbstverständlich müsst ihr die Bezeichner EURER pList nehmen. Hier die Zugriffe für jeder möglichen Datentyp.
Number aus NSDictionary lesen
int x = [[_rootDictionary objectForKey:@"offsetPlayerX"] integerValue];
String aus NSDictionary lesen
NSString *fullText = [_rootDictionary objectForKey:@"text"];
BOOL aus NSDictionary lesen
BOOL powerUpEnabled = [_rootDictionary objectForKey:@"powerUpEnabled"];
Datum aus NSDictionary lesen
NSDate *timestamp = [_rootDictionary objectForKey:@"timestamp"];
Data aus NSDictionary lesen
NSData *someData = [_rootDictionary objectForKey:@"dataObject"];
Es ist sogar möglich komplexe Datenstrukturen in einer pList abzulegen. So können ganze Arrays und weitere Dictionary hinterlegt werden. Wie man am oberen Bild sehen kann habe ich für iBallerburg ein Dictionary für jedes Level angelegt.
NSDictionary aus NSDictionary lesen
NSDictionary *levelDictionary = [_rootDictionary objectForKey:@"levelDictionary"];
Array aus NSDictionary lesen
NSMutableArray *myTerrainDataArray = [_rootDictionary objectForKey:@"levelArray"];
Bis zum nächsten mal.