2010-05-18 11 views
5

Ich muss eine Art von Archivierungsfunktionalität zu einer Objective-C-Trie-Implementierung hinzufügen (NDTrie auf Github), aber ich habe sehr wenig Erfahrung mit C und seine Datenstrukturen.Serialize-Struktur mit Zeigern zu NSData

struct trieNode 
{ 
    NSUInteger key; 
    NSUInteger count, 
    size; 
    id object; 
    __strong struct trieNode ** children; 
    __strong struct trieNode * parent; 
}; 

@interface NDTrie (Private) 
- (struct trieNode*)root; 
@end 

Was ich brauche ist ein NSData mit der Baumstruktur aus dieser Wurzel zu schaffen - oder serialisiert/deserialisiert dem ganzen Baum eine andere Art und Weise (? Konform NSCoding), aber ich habe keine Ahnung, wie man mit NSData arbeiten und eine C-Struktur, die Zeiger enthält.

Die Deserialisierung des resultierenden Objekts wäre von entscheidender Bedeutung, da es sich um ein iPhone-Projekt handelt, das ich bei jedem Start der App in den Hintergrund laden muss.

Was wäre der beste Weg, dies zu erreichen?

Danke!

Antwort

1

Unter der Annahme, müssen mit geraden C bleiben, denn das ist, wie die Dinge bereits eingerichtet sind, was Sie eigentlich ziemlich einfach tun müssen, ist, .

Schreiben Sie einfach eine C-Funktion, um Ihren Baum auf die Festplatte zu schreiben, mit einigen Annahmen über die Reihenfolge (z. B. schreiben Sie zuerst unsere Tiefe, von links nach rechts). Objective-C-Objekte codieren sie in NSData und schreiben die Größe und Bytes davon als Teil Ihres Streams aus.

Wenn Sie die Daten wieder eingelesen haben, rekonstruieren Sie einfach den Baum anhand Ihrer Bestellannahmen und richten Sie die Zeiger auf die untergeordneten Elemente ein. Entarre jedes der eingebetteten Objective-C-Objekte.

Sie können dies wahrscheinlich mit NSCoder irgendwie tun, aber es könnte einfacher sein, die Baumrekonstruktion außerhalb zu machen, da Sie den Baum mit den Argumenten zurückspulen können, die Sie mögen, was mit NSCoding nicht wirklich einfach ist.

Ich habe einige (Desktop OS X) Code, der etwas sehr ähnliches tut, ohne die eingebetteten Objekte, aber es ist ziemlich fummelig, und ich kann es nicht posten.

Eine Optimierung in diesem Code ist das Einlesen der Daten in einen internen Puffer, in MB Chunks (anstatt einer kleinen Anzahl von Bytes zu einer Zeit, für jede Struktur), und dann lesen Sie die Daten aus diesem Puffer, obwohl Ich bin mir nicht sicher, ob jemals ein Benchmarking durchgeführt wurde, und es kann auf jeden Fall einen signifikanten Unterschied auf dem iPhone ausmachen. Es sieht so aus, als gäbe es eine ähnliche Optimierung für das Schreiben, die eher ein Gewinn ist, wie ich es verstehe (iPhone schreibt sind teuer, oder so habe ich gehört).

0

Sie sollten immer den einfachen Weg zuerst versuchen:

// serializing: 
[myTrie writeToFile:myPath atomically:NO]; 

// deserializing 
NDTrie* myTrie = [NDTrie trieWithContentsOfFile:myPath]; 

Wenn das wirklich schnell nicht genug ist, können Sie sich in manuell die zu Grunde liegenden Strukturen Serialisierung.

Edit:

Sie machte deutlich, dass die Menge an Daten, die eine optimierte Implementierung erfordert.

Ich würde vorschlagen, die trieNode Struktur und Zugriffsmethoden zu schreiben, um Indizes anstelle von Zeigern für die parent und children Felder zu verwenden. Die Indizes würden in ein großes C-Array von trieNode-Strukturen zeigen, denen alle Knoten zugewiesen sind.

Dieses C-Array könnte in einem NSData-Objekt im Wrapping-Objekt NDTrie aufbewahrt werden. Serialisierung und Deserialisierung würde dann nur bedeuten, das NSData-Objekt zu speichern/zu laden (Endianess-Probleme beiseite).

+0

Das Problem ist, mein Datensatz ist ziemlich groß, und im Moment kann ich nicht sowohl die temporäre NSArray und die tatsächliche Trie Datenstruktur auf dem Gerätespeicher passen - auch es ist einfach zu langsam, um beide Strukturen zu erstellen. Deshalb habe ich nach einer Möglichkeit gesucht, dieses Array-Re-Creation zu überspringen und das eigentliche Trie-Modell zu serialisieren. – leolobato

2

Reimplementieren Sie die Trie-Knotenstruktur als Objective-C-Klasse. z.B.

@interface TrieNode 
{ 
    NSUinteger key; 
    NSUInteger count; 
    //NSUInteger size; // not needed if you use an NSArray for the children. 
    id object; 
    NSArray* children; 
    TrieNode* parent; 
} 
// methods 
@end 

Dann können Sie den Standard-Objective-C-Mechanismus verwenden, zu archivieren und dearchivieren diese Objekte.

Wenn Sie nach der Implementierung der oben genannten und Profiling Ihren Code, finden Sie Leistung ist ein Problem, können Sie beginnen zu optimieren. Zum Beispiel durch Zugreifen auf Ivars unter Verwendung des C-Struct-Pointerstuffs, z.

aTrieNode->parent; 

oder durch die NSArray mit einem C-Array usw. ersetzen Sie

+0

Das Problem ist, dass ich die gesamte vorhandene Implementierung so umschreiben müsste, dass eine Klasse anstelle dieser Struktur verwendet wird - deshalb suche ich nach einer Möglichkeit, die vorhandene Struktur zu serialisieren, sie sollte wesentlich schneller implementiert werden. – leolobato

+0

Es sieht nicht so aus, als wäre da sehr viel dran. Es ist nur eine Quelldatei und Sie würden die Dinge wahrscheinlich vereinfachen, wenn Sie eine Klasse verwenden. Ich könnte selbst gehen ... – JeremyP

0

Ich glaube, Sie shoud NSCoding Protokoll implementieren: in Ihre initWithCoder: schaffen eine NSArray mit allen children und realloc eine solche Anordnung von struct in encodeWithCoder:.

Auf diese Weise können Sie das ursprüngliche Array der Struktur im Rest des Projekts verwenden.