da1lbi3
da1lbi3

Reputation: 4519

Decode nsData to String Array

I want to decode my nsData to a String Array. I have this code right now:

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

            var stringTerminatorPositions = [Int]()

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

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

                    currentPosition += 1
                }
            }

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

            return decodedStrings
        }

But I get an error on this line: let bytes = UnsafePointer<UInt8>(buffer)

Cannot invoke initializer for type 'UnsafePointer' with an argument list of type '(UnsafeRawPointer)'

Do I need to convert the buffer to a UnsafePointer? If so, how can I do that?

Upvotes: 2

Views: 1131

Answers (1)

Martin R
Martin R

Reputation: 539705

buffer in the enumerateBytes() closure is a UnsafeRawPointer and you have to "rebind" it to an UInt8 pointer in Swift 3:

// let bytes = UnsafePointer<UInt8>(buffer)
let bytes = buffer.assumingMemoryBound(to: UInt8.self)

But why so complicated? You can achieve the same result with

func nsDataToStringArray(nsData: NSData) -> [String] {
    let data = nsData as Data
    return data.split(separator: 0).flatMap { String(bytes: $0, encoding: .utf8) }
}

How does this work?

  • Data is a Sequence of UInt8, therefore
  • split(separator: 0) can be called on it, returning an array of "data slices" (which are views into the source data, not copies).
  • Each "data slice" is again a Sequence of UInt8, from which a String can be created with String(bytes: $0, encoding: .utf8). This is a failable initializer (because the data may be invalid UTF-8).
  • flatMap { ... } returns an array with all non-nil results, i.e. an array with all strings which could be created from valid UTF-8 code sequences between zero bytes.

Upvotes: 2

Related Questions