我对Swift非常陌生。尝试编写一个调用外部C方法的Swift应用。但是,Xcode编译器给出有关类型转换的错误。 C方法原型的形式为:
void * cMethod(const char* string1Path, const char* string2Path, const char* string3Path, const char* string4Path);
Swift代码的要旨是:
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")
}
编译器给出错误:
Cannot convert value of type 'Int8?' to expected argument type 'UnsafePointer<Int8>?'
C方法由桥接头引入。有没有办法将其转换为预期的参数?
注意:此处的Swift代码是几年前从Objective-C文件带来的,并且已被改编为Swift。我使用this Obj-C转Swift转换器,因为我几乎不了解Swift,因此无法阅读Obj-C。我放入的Obj-C衬里的格式为:
NSString * string1 = [[appBundle pathForResource:@"data" ofType:@""] stringByAppendingString:@"/"];
const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]];
答案 0 :(得分:1)
尽管将Int8?
转换为指针很简单(只需将其解包并在将其作为参数传递时使用&
运算符),但是您真正的问题是将字符串转换为{{ 1}}首先是一个错误。 Int8
返回的值将是一条路径,看起来像这样:
Bundle.path(forResource:ofType:)
同时,您尝试将其转换为"/Applications/MyApp.app/Contents/Resources/Init.dat"
,这是一种整数类型,可以使用带有Int8
的初始化程序来存储-128到127之间的值。该初始化程序返回可选内容的原因是因为并非每个字符串都包含-128到127之间的数字,所以如果该字符串是其他字符串,则会得到String
。
像nil
或"37"
这样的字符串可以正确转换,但是上面的路径字符串始终只会给您"-101"
。
您实际上想要在此处执行的操作是将nil
转换为C字符串。有几种不同的方法可以做到这一点,但是我会使用String
的{{1}}功能,就像这样:
URL
请注意,由于未将fileSystemRepresentation
定义为不在该范围内有效,因此请确保此处不要让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.
转义cPath
块。
还要注意,由于withUnsafeFileSystemRepresentation
,如果!
文件实际上不存在于您的应用程序中,这将使您的应用程序崩溃,因此,最好确保将其包括在内。
答案 1 :(得分:1)
如果为我提供了C函数,并在您的Objective-C行中显示了一些代码,我会写这样的东西:
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"))
}
}
在Swift中,当您将String
传递给类型char *
的参数时,Swift会生成一个临时的C字符串缓冲区并传递该缓冲区的地址,您无需调用{ {1}}。
如果const char * string1Path = [string1 cStringUsingEncoding:[NSString defaultCStringEncoding]];
保留了任何指针供以后使用,则您可能需要更复杂的代码,但是尚不清楚我们是否需要像当前说明那样的复杂代码。