Create an Array in Swift from an NSData Object

后端 未结 4 1047
说谎
说谎 2020-12-13 09:13

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

相关标签:
4条回答
  • 2020-12-13 09:49

    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]
    
    0 讨论(0)
  • 2020-12-13 09:50

    If you are dealing with Data to Array (I know for sure my array is going to be [String]), I am quite happy with this:

    NSKeyedUnarchiver.unarchiveObject(with: yourData)

    I hope it helps

    0 讨论(0)
  • 2020-12-13 10:00

    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.

    0 讨论(0)
  • 2020-12-13 10:06

    Here is a generic way to do it.

    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
    

    You must specify the type in the array2 line. Otherwise, the compiler cannot guess.

    0 讨论(0)
提交回复
热议问题