Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift convert string to UnsafeMutablePointer<Int8>

I have a C function mapped to Swift defined as:

func swe_set_eph_path(path: UnsafeMutablePointer<Int8>) -> Void

I am trying to pass a path to the function and have tried:

        var path = [Int8](count: 1024, repeatedValue: 0);
        for i in 0...NSBundle.mainBundle().bundlePath.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)-1
        {
            var range = i..<i+1
            path[i] = String.toInt(NSBundle.mainBundle().bundlePath[range])
        }
        println("\(path)")
        swe_set_ephe_path(&path)

but on the path[i] line I get the error:

'subscript' is unavailable: cannot subscript String with a range of Int

swe_set_ephe_path(NSBundle.mainBundle().bundlePath)

nor

swe_set_ephe_path(&NSBundle.mainBundle().bundlePath)

don't work either

Besides not working, I feel there has got to be a better, less convoluted way of doing this. Previous answers on StackOverflow using CString don't seem to work anymore. Any suggestions?

like image 379
SteveFerg Avatar asked May 05 '15 00:05

SteveFerg


3 Answers

In current version of Swift language you can do it like this (other answers are outdated):

let path = Bundle.main.bundlePath
let param = UnsafeMutablePointer<Int8>(mutating: (path as NSString).utf8String)
like image 28
Leszek Szary Avatar answered Sep 28 '22 06:09

Leszek Szary


Previous answers on StackOverflow using CString don't seem to work anymore

Nevertheless, UnsafePointer<Int8> is a C string. If your context absolutely requires an UnsafeMutablePointer, just coerce, like this:

let s = NSBundle.mainBundle().bundlePath
let cs = (s as NSString).UTF8String
var buffer = UnsafeMutablePointer<Int8>(cs)
swe_set_ephe_path(buffer)

Of course I don't have your swe_set_ephe_path, but it works fine in my testing when it is stubbed like this:

func swe_set_ephe_path(path: UnsafeMutablePointer<Int8>) {
    println(String.fromCString(path))
}
like image 193
matt Avatar answered Sep 28 '22 05:09

matt


It’s actually extremely irritating of the library you’re using that it requires (in the C declaration) a char * path rather than const char * path. (this is assuming the function doesn’t mutate the input string – if it does, you’re in a whole different situation).

If it didn’t, the function would come over to Swift as:

// note, UnsafePointer not UnsafeMutablePointer
func swe_set_eph_path(path: UnsafePointer<Int8>) -> Void

and you could then rely on Swift’s implicit conversion:

let str = "blah"
swe_set_eph_path(str) // Swift implicitly converts Strings 
                      // to const C strings when calling C funcs

But you can do an unsafe conversion quite easily, in combination with the withCString function:

str.withCString { cstr in
    swe_set_eph_path(UnsafeMutablePointer(cstr))
}
like image 32
Airspeed Velocity Avatar answered Sep 28 '22 04:09

Airspeed Velocity