web-dev-qa-db-ja.com

NSDataオブジェクトからSwiftに配列を作成する

私は整数の配列をSwiftのディスクに保存しようとしています。 NSDataオブジェクトに格納して保存することはできますが、配列に戻すことは困難です。 data.bytesを使用してデータに未加工のCOpaquePointerを取得できますが、そのポインターを使用して新しいSwift配列を初期化する方法を見つけることができません。それをするために?

import Foundation

var arr : UInt32[] = [32,4,123,4,5,2];

let data = NSData(bytes: arr, length: arr.count * sizeof(UInt32))

println(data)  //data looks good in the inspector

// now get it back into an array?
34
tassinari

getBytesNSDataメソッドを使用できます。

// the number of elements:
let count = data.length / sizeof(UInt32)

// create array of appropriate length:
var array = [UInt32](count: count, repeatedValue: 0)

// copy bytes into array
data.getBytes(&array, length:count * sizeof(UInt32))

print(array)
// Output: [32, 4, 123, 4, 5, 2]

Swift 3(Xcode 8):Swift 3の更新には、適切な値の意味を持つNS(Mutable)Dataのラッパーである新しい型struct Dataがあります。アクセサメソッドはわずかに異なります。

データへの配列:

var arr: [UInt32] = [32, 4, UInt32.max]
let data = Data(buffer: UnsafeBufferPointer(start: &arr, count: arr.count))
print(data) // <20000000 04000000 ffffffff>

配列へのデータ:

let arr2 = data.withUnsafeBytes {
    Array(UnsafeBufferPointer<UInt32>(start: $0, count: data.count/MemoryLayout<UInt32>.stride))
}
print(arr2) // [32, 4, 4294967295]

Swift 5:の更新

データへの配列:

let arr: [UInt32] = [32, 4, UInt32.max]
let data = Data(buffer: UnsafeBufferPointer(start: arr, count: arr.count))
print(data) // <20000000 04000000 ffffffff>

配列へのデータ:

var arr2 = Array<UInt32>(repeating: 0, count: data.count/MemoryLayout<UInt32>.stride)
_ = arr2.withUnsafeMutableBytes { data.copyBytes(to: $0) }
print(arr2) // [32, 4, 4294967295]
64
Martin R

UnsafeBufferPointerプロトコルを実装しているため、基本的に「配列ポインター」であるSequenceを使用してこれを行うこともできます。

let data = NSData(/* ... */)

// Have to cast the pointer to the right size
let pointer = UnsafePointer<UInt32>(data.bytes)
let count = data.length / 4

// Get our buffer pointer and make an array out of it
let buffer = UnsafeBufferPointer<UInt32>(start:pointer, count:count)
let array = [UInt32](buffer)

これにより、重複する要素を含む空の配列を最初に初期化してから上書きする必要がなくなりますが、それより速いかどうかはわかりません。 Sequenceプロトコルを使用するため、これは高速メモリコピーではなく反復を意味しますが、バッファポインタを渡したときに最適化されるかどうかはわかりません。繰り返しになりますが、「X個の同一の要素を持つ空の配列を作成する」イニシャライザーがどれくらい速いかはわかりません。

14
Daniel Bruce

Data to Arrayを扱っている場合(私の配列が[String]になることは確かです)、私はこれに非常に満足しています:

NSKeyedUnarchiver.unarchiveObject(with:yourData)

私はそれが役立つことを願っています

1
Michel Goñi

以下に一般的な方法を示します。

import Foundation

extension Data {
    func elements <T> () -> [T] {
        return withUnsafeBytes {
            Array(UnsafeBufferPointer<T>(start: $0, count: count/MemoryLayout<T>.size))
        }
    }
}

let array = [1, 2, 3]
let data = Data(buffer: UnsafeBufferPointer(start: array, count: array.count))
let array2: [Int] = data.elements()

array == array2
// IN THE PLAYGROUND, THIS SHOWS AS TRUE

array2行でタイプを指定する必要があります。それ以外の場合、コンパイラは推測できません。

0