30

When I using NSOutputStream's write method

func write(_ buffer: UnsafePointer<UInt8>, maxLength length: Int) -> Int

I don't know how to convert String to UnsafePointer<UInt8> and length

How can I do this in swift?

Imanou Petit
  • 89,880
  • 29
  • 256
  • 218
Chen-Tsu Lin
  • 22,876
  • 16
  • 53
  • 63

10 Answers10

24

You have to convert the string to UTF-8 data first

let string = "foo bar"
let data = string.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!

and then write it to the output stream

let outputStream: NSOutputStream = ... // the stream that you want to write to
let bytesWritten = outputStream.write(UnsafePointer(data.bytes), maxLength: data.length)

The UnsafePointer() cast is necessary because data.bytes has the type UnsafePointer<Void>, and not UnsafePointer<UInt8> as expected by the write() method.


Update for 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) }
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
17

Here is how to do it in Swift 3. Run fine in Swift 4 too

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)
  }
}

To convert from String to UnsafeMutablePointer<Int8>

let cString = strdup("Hello") // UnsafeMutablePointer<Int8>

To convert from UnsafeMutablePointer<Int8> to String

let string = String(cString: cString!) // String
onmyway133
  • 45,645
  • 31
  • 257
  • 263
  • 1
    It's important to keep in mind that the `toPointer()` function returns a pointer to memory allocated on the heap and as such, you should `free()` it when you are finished with it to avoid memory leaks. – Nathan F. Oct 20 '20 at 19:23
7

Swift 4,

Convert String to NSString, then use NSString's methods.

let text = "Hello"
let pointer: UnsafePointer<Int8>? = NSString(string: text).utf8String
let length = NSString(string: text).length
Taimoor Suleman
  • 1,588
  • 14
  • 29
Jirui
  • 139
  • 1
  • 6
6

You can also let Swift do it for you!

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
Lou Zell
  • 5,255
  • 3
  • 28
  • 23
  • Why not just `str.utf8.count`? – Ilya Nov 21 '16 at 16:03
  • 1
    For passing the len? Yup that should work too! I was trying to illustrate that you could pass a String type to a function that expects an UnsafePointer without any explicit casting – Lou Zell Nov 26 '16 at 23:30
6

An answer for people working in Swift 4 now. You can no longer get bytes from a Data object, you have to copy them into an 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)
David Hertel
  • 61
  • 1
  • 1
5

Here is a string extension for Swift 5 that you can convert a string to UnsafePointer<UInt8> and 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)
    }
}

To convert UnsafeMutablePointer<Int8> to String

guard let mutablePointer = "test".toUnsafeMutablePointer() else {
    return
}

let str = String(cString: mutablePointer)
abdullahselek
  • 7,893
  • 3
  • 50
  • 40
4

By far the easiest way (in Swift 5):

let s = "hello, world"
let pointer = UnsafePointer(Array(s.utf8CString))

Not sure how backwards compatible this is.

funct7
  • 3,407
  • 2
  • 27
  • 33
  • This fails: Cannot convert return expression of type 'UnsafePointer' (aka 'UnsafePointer') to return type 'UnsafePointer' – yerlilbilgin Jan 28 '21 at 06:55
  • 1
    int8_t means char actually and UnsafePointer and UnsafePointer are same both of them signed int8. But UInt8 is unsigned char so you need to convert signed to unsigned to resolve it. – Emre Tufekci Feb 24 '21 at 08:15
1

I see there are other answers, and an accepted answer, so it seems you've gotten what you need. I came here because I noticed Swift 5's deprecation warnings for withUnsafeMutableBytes et al, and started testing @abdullahselek's answer, but I noticed in Swift 5 (haven't yet verified if it worked in previous versions) that String is convertible to UnsafePointer<UInt8> in-line, so you can use it in place where an UnsafePointer<UInt8> is expected. In case it helps to see another example, here's our old and updated function, posted here:

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
    )
  }
}

NEW

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
}

With that said, you could use a similar approach to get your stream as follows:

let stream = OutputStream(toBuffer: UnsafeMutablePointer(mutating: someString), capacity: someString.data(using: .utf8)!.count)

(the ! is used to silence the compiler error, but you should avoid force-unwrapping where possible).

BJ Miller
  • 1,536
  • 12
  • 16
  • Hi what is the type of localDerivedKeyData? and which is the output variable in NEW code here? and – Satish Mavani Feb 20 '20 at 22:51
  • `localDerivedKeyData` is `Data`. `derivationStatus` is an `Int32` giving you an output status of the operation. `localDerivedKeyData` is written to, byte by byte, by this operation (assume it's a byte array (Data) that has the proper length, just empty to start) – BJ Miller Feb 25 '20 at 16:51
  • what is the function throws any error/exception, can you share complete function with use? – Satish Mavani Feb 27 '20 at 10:58
1

I've created a Swift extension that includes this feature among many others for generating pointers from Strings.

It includes a full test suite and it supports:

  • 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

If you want to test it out you should be able to directly paste it into a Swift Playground.

Nathan F.
  • 3,250
  • 3
  • 35
  • 69
-1

file.cString(using: String.Encoding.utf8)

kintan
  • 19
  • 1
  • 3