简体   繁体   中英

Convert Int8? to UnsafePointer<Int8>?

I am very new to Swift. Trying to write a Swift app that calls an outside C method. However, the Xcode compiler is giving error about type conversion. The C method prototype is of the form:

void * cMethod(const char* string1Path, const char* string2Path, const char* string3Path, const char* string4Path);

The gist of the Swift code is:

import OpenGLES
import CoreGraphics
import GLKit

var mGLUTWindow: Void?

class myClass {

    mGLUTWindow = nil
    let appBundle = Bundle.main

    let string1 = appBundle.path(forResource: "Init", ofType: "dat")
    let string1Path = Int8((string1?.description)!)

    let string2 = appBundle.path(forResource: "autostart", ofType: "type")
    let string2Path = Int8((string2?.description)!)

    let string3: String? = appBundle.path(forResource: "data", ofType: "") ?? "" + ("/")
    let string3Path = Int8((string3?.description)!)

    mGLUTWindow = cMethod(UnsafePointer(string3Path), string1Path, string2Path, "ios")
}

The compiler gives the error:

Cannot convert value of type 'Int8?' to expected argument type 'UnsafePointer<Int8>?'

The C method is being brought in by a bridging header. Is there a way to convert this to the expected argument?

NOTE: The Swift code here was brought over from an Objective-C file from several years ago and is being adapted to Swift. I used this Obj-C to Swift converter, as I barely understand Swift and cannot read Obj-C. The Obj-C lined I put in were of the form:

NSString * string1 = [[appBundle pathForResource:@"data" ofType:@""] stringByAppendingString:@"/"]; 
const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]];

Although converting an Int8? to a pointer is simple enough (just unwrap it and use the & operator when passing it as an argument), your real problem is that converting your string to an Int8 in the first place is a mistake. The value that Bundle.path(forResource:ofType:) returns is going to be a path, looking something like this:

"/Applications/MyApp.app/Contents/Resources/Init.dat"

Meanwhile, you're trying to convert this to an Int8 , which is an integer type that can store values from -128 to 127, using an initializer that takes a String . The reason this initializer returns an optional is because not every string will contain a number between -128 and 127, so if the string is something else, you get nil .

A string like "37" or "-101" would convert properly, but a path string like the one above will always just give you nil .

What you actually want to do here is to convert your String to a C string. There are a few different ways to do that, but the way I'd do it would be to use URL 's fileSystemRepresentation feature, like so:

let url1 = appBundle.url(forResource: "Init", withExtension: "dat")! // instead of path
url1.withUnsafeFileSystemRepresentation { cPath in
    // cPath here is an UnsafePointer<Int8> that you can pass to C APIs inside this block.
}

// Don't let cPath get out here or bad things will happen.

Note that you need to make sure not to let cPath escape the withUnsafeFileSystemRepresentation block here, because it's not defined to be valid outside of that scope.

Also note that due to the ! , this will crash your app if the Init.dat file doesn't actually exist inside your application, so you'd better make sure you include it.

If I were given the C-function and some code shown as your Objective-C lines, I would write something like this:


var mGLUTWindow: UnsafeRawPointer?

class MyClass {

    func aMethod() {
        let appBundle = Bundle.main

        let string1 = appBundle.path(forResource: "Init", ofType: "dat")!

        let string2 = appBundle.path(forResource: "autostart", ofType: "type")!

        let string3 = (appBundle.path(forResource: "data", ofType: "") ?? "") + ("/")

        mGLUTWindow = UnsafeRawPointer(cMethod(string3, string1, string2, "ios"))
    }
}

In Swift, when you pass String to an argument of type char * , Swift generates a temporary C-string buffer and pass the address of the buffer, you have no need to call something like const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]]; .

If the cMethod keeps any of the pointers for later use, you may need a little more complicated code, but it is not clear that if we need such complicated code as for the current description.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM