Swift - преобразование из UnsafePointer<UInt8> с длиной в строку

Я рассмотрел много подобных вопросов, но все еще не могу заставить компилятор принять это.

Socket Mobile API (в Objective-C) передает ISktScanDecodedData в метод делегата в Swift (данные могут быть двоичными, поэтому я полагаю, поэтому они не представлены в виде строки):

func onDecodedData(device: DeviceInfo?, DecodedData d: ISktScanDecodedData?) {
  let symbology: String = d!.Name()
  let rawData: UnsafePointer<UInt8> = d!.getData()
  let rawDataSize: UInt32 = decoded!.getDataSize()
  // want a String (UTF8 is OK) or Swifty byte array...
}

В C# этот код преобразует необработанные данные в строку:

string s = Marshal.PtrToStringAuto(d.GetData(), d.GetDataSize());

В Swift я могу добраться до UnsafeArrayНо я застрял

let rawArray = UnsafeArray<UInt8>(start: rawData, length: Int(rawDataSize))

В качестве альтернативы я вижу String.fromCString а также NSString.stringWithCharacters, но ни один не примет типы аргументов под рукой. Если бы я мог преобразовать из UnsafePointer<UInt8> в UnsafePointer<()>например, тогда это будет доступно (хотя я не уверен, будет ли это вообще безопасно):

NSData(bytesNoCopy: UnsafePointer<()>, length: Int, freeWhenDone: Bool)

Есть ли очевидный способ получить строку из всего этого?

2 ответа

Решение

Это должно работать:

let data = NSData(bytes: rawData, length: Int(rawDataSize))
let str = String(data: data, encoding: NSUTF8StringEncoding)

Обновление для Swift 3:

let data = Data(bytes: rawData, count: Int(rawDataSize))
let str = String(data: data, encoding: String.Encoding.utf8)

Полученная строка nil если данные не представляют действительную последовательность UTF-8.

Как насчет этого, "чистый" Swift 2.2 вместо использования NSData:

public extension String {

  static func fromCString
    (cs: UnsafePointer<CChar>, length: Int!) -> String?
  {
    if length == .None { // no length given, use \0 standard variant
      return String.fromCString(cs)
    }

    let buflen = length + 1
    var buf    = UnsafeMutablePointer<CChar>.alloc(buflen)
    memcpy(buf, cs, length))
    buf[length] = 0 // zero terminate
    let s = String.fromCString(buf)
    buf.dealloc(buflen)
    return s
  }
}

и Свифт 3:

public extension String {

  static func fromCString
    (cs: UnsafePointer<CChar>, length: Int!) -> String?
  {
    if length == nil { // no length given, use \0 standard variant
      return String(cString: cs)
    }

    let buflen = length + 1
    let buf    = UnsafeMutablePointer<CChar>.allocate(capacity: buflen)
    memcpy(buf, cs, length)
    buf[length] = 0 // zero terminate
    let s = String(cString: buf)
    buf.deallocate(capacity: buflen)
    return s
  }
}

Правда, немного глупо выделять буфер и копировать данные только для добавления нулевого терминатора.

Очевидно, как упоминал Zaph, вам нужно убедиться, что ваши предположения о кодировке строки будут правильными.

Другие вопросы по тегам