2015-11-19 16 views
5

Tôi muốn sử dụng let rawDataFromArray = NSData(bytes: myArray, length: ???), nhưng không biết cách lấy độ dài byte cho mảng của mình. Dưới đây là một số ví dụ về những gì có thể mảng của tôi là:Cách nhận kích thước byte cho mảng tùy ý trong 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 
} 

Tôi không chắc chắn nếu đi qua mọi phần tử của mảng (và trong trường hợp của chuỗi trải qua tất cả các nhân vật, từ biểu tượng cảm xúc có thể có nhiều byte đại diện cho họ) là cách thích hợp để làm điều đó.

Cách nhận kích thước byte cho mảng?
Bất cứ ai có thể cho tôi biết cách thích hợp để làm điều đó?
Hoặc có thể thực tiễn không tốt là chuyển đổi Array thành NSData trong Swift?

Tôi cũng đã xem Converting Swift Array to NSData for persistent storageConverting array of bytes to NSDataCustom Array to NSData, nhưng không thể tìm ra cách nhận kích thước byte cho mảng tùy ý như vậy.

+2

Xem http://stackoverflow.com/questions/25714086/swift-use-sizeof-with-int32-array để biết ví dụ có thể được sử dụng cho một mảng các số nguyên hoặc phao. Nhưng bạn không thể đơn giản xử lý một mảng các chuỗi * như NSData, bởi vì cấu trúc 'String' (có kích thước cố định) chứa các con trỏ đục để lưu trữ ký tự thực tế. –

+0

Cảm ơn @MartinR. Vì vậy, có vẻ như một ý tưởng tồi để chuyển đổi một mảng các chuỗi thành NSData. Bạn có thể giải thích thêm một chút về con trỏ đục không? – Andrej

+1

'struct String' có các thành viên không nằm trong API" có thể nhìn thấy "(nhưng bạn có thể thấy chúng trong trình gỡ lỗi). Một số trong số này là các con trỏ đến dung lượng lưu trữ thực tế được sử dụng cho chuỗi. (Vì vậy, ví dụ, các chuỗi giống hệt nhau có thể * chia sẻ * bộ nhớ.) - Điểm là 'struct String' không phải là khép kín. Nếu bạn gói nó vào NSData, chuyển nó vào một nơi khác và giải nén nó, nó sẽ chứa các con trỏ không hợp lệ. - Tất nhiên bạn * có thể * tạo NSData từ một chuỗi các chuỗi, nhưng phải nối thêm mỗi chuỗi (ví dụ như chuỗi NUL-terminated UTF-8) một cách riêng biệt. –

Trả lời

5

Dường như có sự hiểu lầm: Đối với mỗi loại T, tất cả các trường hợp trong số T có cùng kích thước có thể được tính là sizeof(T). Trong trường hợp của các mảng, có thể có một đệm giữa các phần tử mảng, do đó tổng kích thước cần thiết cho arr1

arr1.count * strideof(Int) 

(so sánh ví dụ Swift: How to use sizeof? cho sự khác biệt tinh tế giữa sizeof()strideof()).

Vì vậy một hàm tổng quát để tạo NSData từ một mảng sẽ

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

Sử dụng withUnsafeBufferPointer() đảm bảo rằng các mảng sử dụng lưu trữ tiếp giáp cho các yếu tố của nó.

Trong trường hợp của các loại "đơn giản" như IntFloat này cung cấp cho các kết quả mong đợi:

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> 

Tuy nhiên, nó là vô ích cho một mảng của chuỗi:

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> 

struct String chứa các con trỏ (ẩn/không có tài liệu) đến bộ nhớ ký tự thực tế.

Một khả năng sẽ được nối thêm mỗi chuỗi như một NUL-chấm dứt UTF-8 chuỗi:

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

Ngoài ra, sử dụng NSKeyedArchiver như trong các chủ đề mà bạn tham chiếu.

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