Swift convert string to UnsafeMutablePointer

2019-01-23 07:14发布

问题:

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?

回答1:

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


回答2:

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


回答3:

I had a static library (someLibrary.a) written in C++ compiled for iOS. The header file (someLibrary.h) had a function exposed like this:

extern long someFunction(char* aString);

The declaration in Swift looks like this:

Int someFunction(aString: UnsafeMutablePointer<Int8>)

I made an extension to String:

extension String {
    var UTF8CString: UnsafeMutablePointer<Int8> {
        return UnsafeMutablePointer((self as NSString).UTF8String)
    }
}

So then I can call the method like so:

someFunction(mySwiftString.UTF8CString)



回答4:

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)