Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an Array in Swift from an NSData Object

I'm trying to store an array of integers to disk in swift. I can get them into an NSData object to store, but getting them back out into an array is difficult. I can get a raw COpaquePointer to the data with data.bytes but can't find a way to initialize a new swift array with that pointer. Does anyone know how to do it?

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? 
like image 916
tassinari Avatar asked Jul 01 '14 17:07

tassinari


People also ask

How do you create an array of variables in Swift?

Array in swift is written as **Array < Element > **, where Element is the type of values the array is allowed to store. The type of the emptyArray variable is inferred to be [String] from the type of the initializer. The groceryList variable is declared as “an array of string values”, written as [String].

How do you create an array of arrays in Swift?

In Swift, creating a multi-dimensional array is just a matter of adding another set of brackets. For example, to turn our [String] array into an array of arrays, you would just write [[String]] .

How do I initialize an array in Swift?

To initialize a set with predefined list of unique elements, Swift allows to use the array literal for sets. The initial elements are comma separated and enclosed in square brackets: [element1, element2, ..., elementN] .

How do you create an empty array in Swift?

To create an empty string array in Swift, specify the element type String for the array and assign an empty array to the String array variable.


2 Answers

You can use the getBytes method of 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] 

Update for Swift 3 (Xcode 8): Swift 3 has a new type struct Data which is a wrapper for NS(Mutable)Data with proper value semantics. The accessor methods are slightly different.

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> 

Data to Array:

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

Update for 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> 

Data to Array:

var arr2 = Array<UInt32>(repeating: 0, count: data.count/MemoryLayout<UInt32>.stride) _ = arr2.withUnsafeMutableBytes { data.copyBytes(to: $0) } print(arr2) // [32, 4, 4294967295] 
like image 182
Martin R Avatar answered Sep 24 '22 09:09

Martin R


It's also possible to do this using an UnsafeBufferPointer, which is essentially an "array pointer", as it implements the Sequence protocol:

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) 

This eliminates the need for initializing an empty array with duplicated elements first, to then overwrite it, although I have no idea if it's any faster. As it uses the Sequence protocol this implies iteration rather than fast memory copy, though I don't know if it's optimized when passed a buffer pointer. Then again, I'm not sure how fast the "create an empty array with X identical elements" initializer is either.

like image 23
Daniel Bruce Avatar answered Sep 25 '22 09:09

Daniel Bruce