在 iOS/MacOS 中调用本机函数时,如何将复杂的 swift 数据类型传递给 C 数据类型?
How can I pass complex swift datatypes to C datatypes when calling native functions in iOS/MacOS?
我设法获得了一个基本的 dylib,我已将其包含在一个框架中,该框架允许我传入一个 Int 和 returns 以及 Int 工作但我将如何传递并且 return 更复杂从 swift 到 C dylib?
的指针、字节数组或实际数据结构等数据类型
是否有任何教程或资源 map/pass/convert 从 swift 数据类型到 C 数据类型,反之亦然,例如在 JNI 中 java?
解释 C 结构并从 Swift 端的 c-dylib 动态提取函数的示例如下所示:
.c 文件
Person *get_person() {
Person *p = malloc(sizeof(Person));
p->first_name = strdup("Branford");
p->last_name = strdup("Marsalis");
p->age = 60;
return p;
}
void free_person(Person *person) {
free(person->first_name);
free(person->last_name);
free(person);
}
.h 文件
typedef struct {
char *first_name;
char *last_name;
int age;
} Person;
Swift
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) { [=12=].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)
测试
此示例的调试控制台输出如下所示:
Branford
Marsalis
60
从Swift到C
假设在 .c 中:
void print_person(Person *person) {
printf("%s %s is %d years old\n",
person->first_name,
person->last_name,
person->age);
}
然后在 Swift 一侧可以写:
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()
这将在控制台上产生以下输出:
Norah Jones is 41 years old
我设法获得了一个基本的 dylib,我已将其包含在一个框架中,该框架允许我传入一个 Int 和 returns 以及 Int 工作但我将如何传递并且 return 更复杂从 swift 到 C dylib?
的指针、字节数组或实际数据结构等数据类型是否有任何教程或资源 map/pass/convert 从 swift 数据类型到 C 数据类型,反之亦然,例如在 JNI 中 java?
解释 C 结构并从 Swift 端的 c-dylib 动态提取函数的示例如下所示:
.c 文件
Person *get_person() {
Person *p = malloc(sizeof(Person));
p->first_name = strdup("Branford");
p->last_name = strdup("Marsalis");
p->age = 60;
return p;
}
void free_person(Person *person) {
free(person->first_name);
free(person->last_name);
free(person);
}
.h 文件
typedef struct {
char *first_name;
char *last_name;
int age;
} Person;
Swift
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) { [=12=].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)
测试
此示例的调试控制台输出如下所示:
Branford
Marsalis
60
从Swift到C
假设在 .c 中:
void print_person(Person *person) {
printf("%s %s is %d years old\n",
person->first_name,
person->last_name,
person->age);
}
然后在 Swift 一侧可以写:
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()
这将在控制台上产生以下输出:
Norah Jones is 41 years old