【发布时间】:2014-08-28 17:47:57
【问题描述】:
当我使用NSOutputStream 的write 方法时
func write(_ buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int
我不知道如何将String 转换为UnsafePointer<UInt8> 和长度
我怎样才能快速做到这一点?
【问题讨论】:
当我使用NSOutputStream 的write 方法时
func write(_ buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int
我不知道如何将String 转换为UnsafePointer<UInt8> 和长度
我怎样才能快速做到这一点?
【问题讨论】:
您必须先将字符串转换为 UTF-8 数据
let string = "foo bar"
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
然后将其写入输出流
let outputStream: NSOutputStream = ... // the stream that you want to write to
let bytesWritten = outputStream.write(UnsafePointer(data.bytes), maxLength: data.length)
UnsafePointer() 强制转换是必要的,因为 data.bytes 具有 UnsafePointer<Void> 类型,而不是 write() 所期望的 UnsafePointer<UInt8>
方法。
Swift 3 更新:
let string = "foo bar"
// Conversion to UTF-8 data (cannot fail):
let data = string.data(using: String.Encoding.utf8)!
// Write to output stream:
let outputStream: NSOutputStream = ... // the stream that you want to write to
let bytesWritten = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }
【讨论】:
UnsafePointer<UInt8>?和UnsafePointer<Void>有什么不同吗?我发现有一个 UTF8 结构和一个 String.UTF8View 嵌套类型,但不知道如何使用它们。
NSData。还有一个withCString 方法产生UnsafePointer<Int8>。
String 类型的 Swift 变量。我需要将其转换为UnsafePointer<UInt8>。
这是在 Swift 3 中的操作方法。在 Swift 4 中也可以正常运行
extension String {
func toPointer() -> UnsafePointer<UInt8>? {
guard let data = self.data(using: String.Encoding.utf8) else { return nil }
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
let stream = OutputStream(toBuffer: buffer, capacity: data.count)
stream.open()
data.withUnsafeBytes({ (p: UnsafePointer<UInt8>) -> Void in
stream.write(p, maxLength: data.count)
})
stream.close()
return UnsafePointer<UInt8>(buffer)
}
}
从String 转换为UnsafeMutablePointer<Int8>
let cString = strdup("Hello") // UnsafeMutablePointer<Int8>
从UnsafeMutablePointer<Int8> 转换为String
let string = String(cString: cString!) // String
【讨论】:
toPointer() 函数返回一个指向在堆上分配的内存的指针,因此,当你完成它以避免内存泄漏时,你应该free() 它。
斯威夫特 4,
将 String 转换为 NSString,然后使用 NSString 的方法。
let text = "Hello"
let pointer: UnsafePointer<Int8>? = NSString(string: text).utf8String
let length = NSString(string: text).length
【讨论】:
您也可以让 Swift 为您代劳!
import Foundation
// Example function:
func printUTF8Vals(_ ptr: UnsafePointer<UInt8>, _ len: Int) {
for i in 0..<len {
print(ptr[i])
}
}
// Call it:
let str = "Hello"
printUTF8Vals(str, str.lengthOfBytes(using: String.Encoding.utf8))
// Prints:
// 72
// 101
// 108
// 108
// 111
【讨论】:
str.utf8.count?
现在使用 Swift 4 工作的人的答案。您不能再从 Data 对象中获取字节,您必须将它们复制到 UnsafeMutablePointer 中
let helloWorld = "Hello World!"
let data = helloWorld.data(using: String.Encoding.utf8, allowLossyConversion: false)!
var dataMutablePointer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
//Copies the bytes to the Mutable Pointer
data.copyBytes(to: dataMutablePointer, count: data.count)
//Cast to regular UnsafePointer
let dataPointer = UnsafePointer<UInt8>(dataMutablePointer)
//Your stream
oStream.write(dataPointer, maxLength: data.count)
【讨论】:
这是 Swift 5 的字符串扩展,您可以将字符串转换为 UnsafePointer<UInt8> 和 UnsafeMutablePointer<Int8>
extension String {
func toUnsafePointer() -> UnsafePointer<UInt8>? {
guard let data = self.data(using: .utf8) else {
return nil
}
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: data.count)
let stream = OutputStream(toBuffer: buffer, capacity: data.count)
stream.open()
let value = data.withUnsafeBytes {
$0.baseAddress?.assumingMemoryBound(to: UInt8.self)
}
guard let val = value else {
return nil
}
stream.write(val, maxLength: data.count)
stream.close()
return UnsafePointer<UInt8>(buffer)
}
func toUnsafeMutablePointer() -> UnsafeMutablePointer<Int8>? {
return strdup(self)
}
}
将UnsafeMutablePointer<Int8> 转换为String
guard let mutablePointer = "test".toUnsafeMutablePointer() else {
return
}
let str = String(cString: mutablePointer)
【讨论】:
迄今为止最简单的方法(在 Swift 5 中):
let s = "hello, world"
let pointer = UnsafePointer(Array(s.utf8CString))
不确定它的向后兼容性如何。
【讨论】:
我看到还有其他答案,以及一个公认的答案,所以看来你已经得到了你需要的东西。我来到这里是因为我注意到 Swift 5 对 withUnsafeMutableBytes 等人的弃用警告,并开始测试 @abdullahselek 的答案,但我注意到在 Swift 5 中(尚未验证它是否在以前的版本中有效)String 可转换为UnsafePointer<UInt8> 内联,因此您可以在需要 UnsafePointer<UInt8> 的地方使用它。如果看到另一个例子有帮助,这里是我们旧的和更新的函数,张贴在这里:
旧
let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { derivedKeyBytes in
salt.withUnsafeBytes { saltBytes in
CCKeyDerivationPBKDF(
CCPBKDFAlgorithm(kCCPBKDF2),
password,
passwordData.count,
saltBytes,
salt.count,
algorithm,
UInt32(rounds),
derivedKeyBytes,
derivedKeyData.count
)
}
}
新
let derivationStatus = localDerivedKeyData.withUnsafeMutableBytes { (outputBytes: UnsafeMutableRawBufferPointer) -> Int32 in
let status = CCKeyDerivationPBKDF(
CCPBKDFAlgorithm(kCCPBKDF2),
password, // a String
passwordData.count, // just the password String converted to Data
String(data: salt, encoding: .utf8), // converts salt (Data) to String
salt.count,
algorithm,
UInt32(rounds),
outputBytes.baseAddress?.assumingMemoryBound(to: UInt8.self),
derivedKeyData.count
)
return status
}
话虽如此,您可以使用类似的方法来获取您的流,如下所示:
let stream = OutputStream(toBuffer: UnsafeMutablePointer(mutating: someString), capacity: someString.data(using: .utf8)!.count)
(! 用于消除编译器错误,但应尽可能避免强制展开)。
【讨论】:
localDerivedKeyData 是 Data。 derivationStatus 是一个 Int32,为您提供操作的输出状态。 localDerivedKeyData 通过此操作逐字节写入(假设它是一个具有适当长度的字节数组(数据),开始时为空)
我已经创建了一个 Swift 扩展,其中包括了许多其他用于从字符串生成指针的功能。
它包括一个完整的测试套件,它支持:
myString.stackPointer() -> UnsafePointer<Int8>?myString.mutableStackPointer() -> UnsafeMutablePointer<Int8>?myString.withUnsignedStackPointer { (ptr: UnsafePointer<UInt8>?) in myString.withUnsignedMutableStackPointer { (ptr: UnsafeMutablePointer<UInt8>?) in myString.heapPointer() -> UnsafePointer<Int8>?myString.mutableHeapPointer() -> UnsafeMutablePointer<Int8>?myString.unsignedHeapPointer() -> UnsafePointer<UInt8>?myString.unsignedMutableHeapPointer() -> UnsafeMutablePointer<UInt8>?https://gist.github.com/nathan-fiscaletti/892e074dc14e6707603414cd2d80c287
如果您想对其进行测试,您应该可以直接将其粘贴到 Swift Playground 中。
【讨论】:
file.cString(使用:String.Encoding.utf8)
【讨论】: