当我使用NSOutputStream
的write
方法时
func write(_ buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int
我不知道如何将String
转换为UnsafePointer<UInt8>
并获取长度。
在Swift中,我该怎么做?
你需要先将字符串转换为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>
,而不是 UnsafePointer<UInt8>
,这与 write()
方法所期望的类型不符。
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) }
以下是如何在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()
释放它,以避免内存泄漏。 - Nathan F.Swift 4
将String转换为NSString,然后使用NSString的方法。
let text = "Hello"
let pointer: UnsafePointer<Int8>? = NSString(string: text).utf8String
let length = NSString(string: text).length
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)
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
呢? - Ilya这里是一个针对 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))
不确定这个向后兼容性有多强。
withUnsafeMutableBytes
等的弃用警告,并开始测试 @abdullahselek 的答案,但我在 Swift 5 中(尚未验证它在之前的版本中是否有效)发现 String
可以直接转换为 UnsafePointer<UInt8>
,因此您可以在需要 UnsafePointer<UInt8>
的地方使用它。如果需要看到另一个示例,这是我们旧的和更新的函数,发布在这里:
OLD
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
中(假设它是一个字节数组(Data),具有适当的长度,但一开始为空)。 - BJ Millerhttps://gist.github.com/nathan-fiscaletti/892e074dc14e6707603414cd2d80c287
如果你想要测试它,你应该能够直接将它粘贴到 Swift Playground 中。
file.cString(使用String.Encoding.utf8)
UnsafePointer<UInt8>
?与UnsafePointer<Void>
有什么不同吗?我发现有一个UTF8
结构体和一个String.UTF8View
嵌套类型,但不知道如何使用它们。 - IsuruString
的 Swift 变量,我需要将其转换为UnsafePointer<UInt8>
。 - Isuru