2015-11-19 5 views
5

Ich möchte let rawDataFromArray = NSData(bytes: myArray, length: ???) verwenden, weiß aber nicht, wie die Byte-Länge für mein Array zu erhalten. Hier sind einige Beispiele von dem, was könnte mein Array sein:Wie erhalten Sie Bytes Größe für beliebige Array in Swift?

let arr1 = [1, 2, 3] 
let arr2 = [1.0, 23556789000.0] 
let arr3 = ["hello", "ok", ""] 

func arrayLength(myArray: Array) -> Int { 
    var bytes = 0 
    for object in myArray { 
     // not sure what to do here 
    } 
    return bytes 
} 

Ich bin nicht sicher, ob durch jedes Element des Arrays gehen (und im Fall von Strings durch jedes Zeichen gehen, da Emojis mehr Bytes haben könnte sie vertretenden) ist der richtige Weg, es zu tun.

Wie erhalten Bytes Größe für Array?
Kann mir jemand den richtigen Weg sagen, es zu tun?
Oder ist es vielleicht nur, dass es keine gute Praxis ist, Array in Swift zu NSData zu konvertieren?

habe gesehen Converting Swift Array to NSData for persistent storage und Converting array of bytes to NSData und Custom Array to NSData, konnte aber nicht herausfinden, wie Bytes Größe für eine solche willkürliche Anordnung zu erhalten. Ich habe auch

+2

Siehe http://stackoverflow.com/questions/25714086/swift-use-sizeof-with-int32-array für ein Beispiel, das für ein Array von Ganzzahlen oder Gleitkommazahlen verwendet werden kann. Aber Sie können nicht einfach ein Array von * strings * als NSData behandeln, da die 'String'-Struktur (die eine feste Größe hat) opake Zeiger auf den eigentlichen Zeichenspeicher enthält. –

+0

Danke @MartinR. Es sieht also nach einer schlechten Idee aus, ein Array von Strings in NSData zu konvertieren. Können Sie etwas mehr erklären, was undurchsichtige Zeiger sind? – Andrej

+1

'struct String' hat Mitglieder, die nicht Teil der" sichtbaren "API sind (aber Sie können sie im Debugger sehen). Einige davon sind Zeiger auf den tatsächlichen Speicher, der für die Zeichenfolge verwendet wird. (So ​​können zum Beispiel identische Strings * Speicher * teilen.) - Der Punkt ist, dass 'struct String' nicht in sich abgeschlossen ist. Wenn Sie das in NSData packen, übertragen Sie es woanders und entpacken Sie es, es wird ungültige Zeiger enthalten. - Natürlich * können * Sie NSData aus einem Array von Strings erstellen, müssen aber jeden String (z. B. als NUL-terminierte UTF-8-String) separat anhängen. –

Antwort

5

Es scheint ein Missverständnis zu sein: Für jeden Typ T alle Instanzen von T die gleiche Größe haben, die als sizeof(T) berechnet werden kann. Im Fall von Arrays, kann es ein padding zwischen Array-Elementen sein, somit die Gesamtgröße für arr1 erforderlich ist

arr1.count * strideof(Int) 

(Vergleiche z.B. Swift: How to use sizeof? für die feinen Unterschiede zwischen sizeof() und strideof()).

Daher ist eine generische Funktion NSData aus einem Array erzeugen würde

extension Array { 
    func asData() -> NSData { 
     return self.withUnsafeBufferPointer({ 
      NSData(bytes: $0.baseAddress, length: count * strideof(Element)) 
     }) 
    } 
} 

Mit withUnsafeBufferPointer() garantiert sein, dass das Array sequenzielle Speicher für seine Elemente verwendet.

Im Fall von "einfachen" Typen wie Int und Float Dies gibt die erwarteten Ergebnisse:

let arr1 = [1, 2, 3] 
print(arr1.asData()) 
// <01000000 00000000 02000000 00000000 03000000 00000000> 

let arr2 = [1.0, 23556789000.0] 
print(arr2.asData()) 
// <00000000 0000f03f 0000204c 60f01542> 

Es ist jedoch für eine Reihe von Strings nutzlos:

let arr3 = ["hello", "ok", ""] 
print(arr3.asData()) 
// <945b2900 01000000 05000000 00000000 00000000 00000000 9a5b2900 01000000 02000000 00000000 00000000 00000000 068d2900 01000000 02000000 00000080 00000000 00000000> 

weil struct String enthält (versteckte/undokumentierte) Zeiger auf den eigentlichen Zeichenspeicher .

Eine Möglichkeit wäre, jede Zeichenfolge als NUL-terminiert UTF-8-String anhängen:

let data3 = NSMutableData() 
arr3.forEach { string in 
    string.withCString { 
     data3.appendBytes($0, length: Int(strlen($0)) + 1) 
    } 
} 
print(data3) 
// <68656c6c 6f006f6b 00f09f91 8d00> 

Alternativ verwenden NSKeyedArchiver wie in den Themen, die Sie verwiesen.

Verwandte Themen