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.