2014-07-01 30 views
33

Tôi đang cố lưu một mảng các số nguyên vào đĩa nhanh chóng. Tôi có thể đưa chúng vào một đối tượng NSData để lưu trữ, nhưng việc đưa chúng trở lại một mảng là rất khó. Tôi có thể lấy COpaquePointer thô cho dữ liệu với data.bytes nhưng không thể tìm cách khởi tạo mảng nhanh mới bằng con trỏ đó. Có ai biết làm thế nào để làm điều đó?Tạo một mảng trong Swift từ một đối tượng NSData

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? 
+5

lưu trữ/hủy lưu trữ, đó là cách dễ dàng hơn và phổ biến nhất để thực hiện việc như vậy. – holex

+1

lưu trữ/unarchive treo ở đây bởi vì nó không phải là một mảng của các đối tượng, chỉ int giá trị. Tôi sẽ phải thay đổi mảng của tôi thành các đối tượng Int. – tassinari

+0

chắc chắn, bởi vì bạn có thể lưu trữ các đối tượng chỉ phù hợp với giao thức 'NSCoding'. nếu bạn thay đổi mảng từ 'Array ' thành 'Array ', bạn sẽ có thể lưu trữ ngay lập tức. – holex

Trả lời

57

Bạn có thể sử dụng phương pháp getBytes của 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] 

Cập nhật cho Swift 3 (Xcode 8): Swift 3 có một loại mới struct Data mà là một wrapper cho NS(Mutable)Data với ngữ nghĩa giá trị thích hợp. Các phương thức truy cập hơi khác nhau.

Array dữ liệu:

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

dữ liệu để Array:

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

Cảm ơn bạn, hoạt động rất tốt. – tassinari

+1

Swift thay đổi cách viết các khai báo mảng, trong Xcode Beta 5 bạn nhận được một lỗi nói: 'Các loại mảng bây giờ được viết với các dấu ngoặc xung quanh loại phần tử'.Vì vậy, trong dòng thứ 2 của mã của bạn chính xác là: 'var array = [UInt32] (count: count, repeatValue: 6)' – Lucien

+0

@Lucien: Bạn nói đúng, cảm ơn, tôi đã sửa nó. –

12

Nó cũng có thể làm điều này bằng một UnsafeBufferPointer, mà bản chất là một "con trỏ mảng", như nó triển khai giao thức 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) 

Điều này loại bỏ sự cần thiết phải khởi tạo một mảng trống với các yếu tố trùng lặp trước, sau đó ghi đè lên nó, mặc dù tôi không có ý tưởng nếu nó nhanh hơn. Vì nó sử dụng giao thức Sequence, điều này ngụ ý việc lặp lại thay vì sao chép bộ nhớ nhanh, mặc dù tôi không biết liệu nó có được tối ưu hóa khi truyền con trỏ đệm hay không. Sau đó, một lần nữa, tôi không chắc chắn nhanh như thế nào "tạo ra một mảng trống với X yếu tố giống hệt nhau" khởi tạo là một trong hai.

+0

Điều này dường như hiện đang hoạt động tốt hơn, vì phương thức getBytes đã gây ra sự cố. – voidref

+5

dường như getBytes nhanh hơn nhiều so với cái này. Đối với 1349890 byte sử dụng một "con trỏ mảng" mất 0,034 giây, trong khi getBytes chỉ 0,005 giây – f3n1kc

+0

Nhận được lỗi sau: 'UnsafePointer ' với một danh sách đối số của loại '(UnsafeRawPointer)'. vì data.bytes là UnsafeRawPointer. Tôi chỉ cố gắng viết mã tương đương cho const char * bytes = [dữ liệu byte]; – Alix

0

Đây là cách chung để thực hiện.

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 

Bạn phải chỉ định loại trong dòng array2. Nếu không, trình biên dịch không thể đoán được.

0

Nếu bạn đang đối phó với dữ liệu để Array (Tôi biết chắc chắn mảng của tôi sẽ là [Chuỗi]), tôi khá hài lòng với điều này:

NSKeyedUnarchiver.unarchiveObject (với: yourData)

Tôi hy vọng nó sẽ giúp

Các vấn đề liên quan