How to Convert String Array to NSData, NSData to String Array?

I tested this in iOS 9

func test() {
    let originalStrings = ["Apple", "Pear", "Orange"]
    NSLog("Original Strings: \(originalStrings)")

    let encodedStrings = stringArrayToNSData(originalStrings)
    let decodedStrings = nsDataToStringArray(encodedStrings)
    NSLog("Decoded Strings: \(decodedStrings)")
}

func stringArrayToNSData(array: [String]) -> NSData {
    let data = NSMutableData()
    let terminator = [0]
    for string in array {
        if let encodedString = string.dataUsingEncoding(NSUTF8StringEncoding) {
            data.appendData(encodedString)
            data.appendBytes(terminator, length: 1)
        }
        else {
            NSLog("Cannot encode string \"\(string)\"")
        }
    }
    return data
}

func nsDataToStringArray(data: NSData) -> [String] {
    var decodedStrings = [String]()

    var stringTerminatorPositions = [Int]()

    var currentPosition = 0
    data.enumerateByteRangesUsingBlock() {
        buffer, range, stop in

        let bytes = UnsafePointer<UInt8>(buffer)
        for var i = 0; i < range.length; ++i {
            if bytes[i] == 0 {
                stringTerminatorPositions.append(currentPosition)
            }
            ++currentPosition
        }
    }

    var stringStartPosition = 0
    for stringTerminatorPosition in stringTerminatorPositions {
        let encodedString = data.subdataWithRange(NSMakeRange(stringStartPosition, stringTerminatorPosition - stringStartPosition))
        let decodedString =  NSString(data: encodedString, encoding: NSUTF8StringEncoding) as! String
        decodedStrings.append(decodedString)
        stringStartPosition = stringTerminatorPosition + 1
    }

    return decodedStrings
}

Swift 4.2

[String] -> JSON -> Data

func stringArrayToData(stringArray: [String]) -> Data? {
  return try? JSONSerialization.data(withJSONObject: stringArray, options: [])
}

Data -> JSON -> [String]

func dataToStringArray(data: Data) -> [String]? {
  return (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String]
}

For a direct answer to your question, you could ask each string in your array for its thisString.dataUsingEncoding(_:) and append the result to an NSMutableData instance until you're all done.

let stringsData = NSMutableData()
for string in strings {

    if let stringData = string.dataUsingEncoding(NSUTF16StringEncoding) {

        stringsData.appendData(stringData)

    } else {

        NSLog("Uh oh, trouble!")

    }

}

Of course this doesn't help you if you want to separate the strings later, so what we really need to know is how / in what environment do you intend to consume this data on the other end of your connection? If the other end uses Cocoa as well, consider just packaging it as a PLIST. Since NSString, NSArray, and NSData are all property list types, you can just archive your NSArray of NSString instances directly:

let arrayAsPLISTData = NSKeyedArchiver.archivedDataWithRootObject(strings)

...then transfer the resulting NSData instance to the Cocoa-aware destination and then:

if let newStrings: [String] = NSKeyedUnarchiver.unarchiveObjectWithData(arrayAsPLISTData) as? [String] {

    // ... do something

}

Tags:

Swift