How can I pass complex swift datatypes to C datatypes when calling native functions in iOS/MacOS?
我设法获得了一个包含在框架中的基本 dylib,它允许我传入 Int 并返回和 Int 工作,但我将如何传递和返回更复杂的数据类型,如指针、字节数组或实际数据结构快速到 C dylib?
是否有任何教程或资源可以将 swift 数据类型映射/传递/转换为 C 数据类型,反之亦然,就像在 JNI for java 中一样?
在 Swift 端解释 C 结构并从 c-dylib 动态提取函数的示例如下所示:
.c 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 |
.h 文件
1 2 3 4 5 | typedef struct { char *first_name; char *last_name; int age; } Person; |
斯威夫特
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | typealias getPersonFunc = @convention(c) () -> UnsafeMutablePointer<Person> typealias freePersonFunc = @convention(c) (UnsafeMutablePointer<Person>) -> Void ... let handle = dlopen("libsimple.dylib", RTLD_LOCAL|RTLD_NOW) let get_person_sym = dlsym(handle,"get_person") let getPerson = unsafeBitCast(get_person_sym, to: getPersonFunc.self) let cPerson = getPerson() let person = cPerson.withMemoryRebound(to: Person.self, capacity: 1) { $0.pointee } let firstName = String(cString: UnsafeRawPointer(person.first_name).assumingMemoryBound(to: CChar.self)) let lastName = String(cString: UnsafeRawPointer(person.last_name).assumingMemoryBound(to: CChar.self)) print(firstName) print(lastName) print(person.age) let free_person_sym = dlsym(handle,"free_person") let freePerson = unsafeBitCast(free_person_sym, to: freePersonFunc.self) freePerson(cPerson) dlclose(handle) |
测试
此示例在调试控制台上的输出如下所示:
1 2 3 | Branford Marsalis 60 |
从 Swift 到 C
假设在 .c:
1 2 3 4 5 6 7 | void print_person(Person *person) { printf("%s %s is %d years old\ ", person->first_name, person->last_name, person->age); } |
然后在 Swift 方面可以这样写:
1 2 3 4 5 6 7 8 9 10 | typealias printPersonFunc = @convention(c) (UnsafeMutablePointer<Person>) -> Void ... let newPerson = UnsafeMutablePointer<Person>.allocate(capacity: 1) newPerson.pointee.first_name = UnsafeMutablePointer<Int8>(mutating: ("Norah" as NSString).utf8String) newPerson.pointee.last_name = UnsafeMutablePointer<Int8>(mutating: ("Jones" as NSString).utf8String) newPerson.pointee.age = 41 let print_person_sym = dlsym(handle,"print_person") let printPerson = unsafeBitCast(print_person_sym, to: printPersonFunc.self) printPerson(newPerson) newPerson.deallocate() |
这将在控制台上给出以下输出:
1 | Norah Jones is 41 years old |