Подтвердить что ты не робот

Создание массива в Swift из объекта NSData

Я пытаюсь сохранить массив целых чисел на диск в swift. Я могу получить их в объект NSData для хранения, но получить их обратно в массив сложно. Я могу получить raw COpaquePointer для данных с помощью data.bytes, но не могу найти способ инициализировать новый 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?
4b9b3361

Ответ 1

Вы можете использовать метод getBytes из NSData:

// 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 имеет новый тип struct Data которая является оберткой для NS(Mutable)Data с правильной семантикой значения. Методы доступа немного отличаются.

Array to 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:

Array to Data:

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]

Ответ 2

Это также можно сделать с помощью 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 одинаковыми элементами".

Ответ 3

Если вы имеете дело с Data to Array (я точно знаю, что мой массив будет [String]), я вполне доволен этим:

NSKeyedUnarchiver.unarchiveObject(с: yourData)

Я надеюсь, что это поможет

Ответ 4

Вот общий способ сделать это.

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. В противном случае компилятор не может догадаться.