【问题标题】:Swift - converting from UnsafePointer<UInt8> with length to StringSwift - 从具有长度的 UnsafePointer<UInt8> 转换为字符串
【发布时间】:2014-07-30 16:59:49
【问题描述】:

我考虑了很多类似的问题,但仍然无法让编译器接受这个。

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.fromCStringNSString.stringWithCharacters,但它们都不会接受手头的参数类型。例如,如果我可以从 UnsafePointer&lt;UInt8&gt; 转换为 UnsafePointer&lt;()&gt;,那么这将是可用的(尽管我不确定它是否安全):

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

有没有一种明显的方法可以从这一切中得到一个字符串?

【问题讨论】:

  • 想告诉我们Marshal 是做什么的吗?带有ds 的十六进制转储的示例会很棒。
  • @Zaph Marshal 是一个 C# 类,具有用于在各种类型之间进行转换的实用方法,包括从指向数据块的指针到拥有实际字符串的好方法。跨度>

标签: swift type-conversion


【解决方案1】:

这应该可行:

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 序列。

【讨论】:

  • 谢谢!我看到了以下内容的自动完成功能,但认为它不会起作用:NSData(bytes: ConstUnsafePointer&lt;()&gt;, length: Int)
  • 注意:不是所有的数据都可以组成一个UTF8字符串。
  • 谢谢,非常有帮助。
【解决方案2】:

怎么样,'纯' 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
  }
}

和 Swift 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 所提到的,您需要确保您对字符串编码的假设是正确的。

【讨论】:

  • ConstUnsafePointer 在 Swift 中不再可用。你能更新你的帖子吗?
  • 完成。 ConstUnsafePointer 现在是 UnsafePointer,另一个是 UnsafeMutablePointer。
  • memcpy(buf, cs, UInt(lengh)) 应该是memcpy(buf, cs, Int(length))
  • 完成,谢谢。 memcpy() 的 API 映射在一些 Swift 版本中发生了变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-26
相关资源
最近更新 更多