一旦为我分配了iOS任务-具有特定加密功能的VPN客户端。
传统上,我们公司有自己的密码学,有一个现成的C语言实现。
在本文中,我将告诉您如何在C和Swift之间结交朋友。
为了清楚起见,作为示例,我们将编写一个简单的函数来转换C语言中的字符串并从Swift中调用它。
此类任务的主要困难是参数传递和返回值。让我们谈谈他们。让我们有一个功能:
uint8_t* flipString(uint8_t* str, int strlen){
uint8_t* result = malloc(strlen);
int i;
int j=0;
for(i = strlen-1; i>=0; --i){
result[j] = str[i];
j++;
}
return result;
}
该函数获取一个指向要反转的字节数组和字符串长度的指针。我们返回一个指向结果字节数组的指针。牢记malloc。贯穿,写下,返回。
我们用函数的标题创建MyCFile.h。添加Bridging-Header.h,其中连接了相同的MyCFile.h。
进一步的类型转换。让我们从一个简单的事情开始-int是Int32。然后是指针。快速有几个指针。我们对UnsafeMutablePointer感兴趣。
let str = "qwerty"
var array: [UInt8] = Array(str.utf8)
let stringPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: array.count)
stringPointer.initialize(from: &array, count: array.count)
guard let res = flipString(stringPointer, Int32(array.count)) else {return}
从给定的字符串创建一个UInt8数组(所以它是一个字节)。我们创建一个指向一定大小数据的指针。我们指出。打电话,看看不是零。
而且,如果使用传递的指针看起来一切都很简单,则res当前为UnsafeMutablePointer?类型。单击几次,绕过StackOverflow,我们找到了pointee属性。使用此属性,可以通过此指针访问内存。我们尝试使用此属性扩展单词“ qwerty”,然后在其中出现... Badum-ts ...“ 121”。好的,鼓声是多余的,但是结果却不是我想要的。
虽然,如果您考虑一下,一切都是合乎逻辑的。在Swift中,我们的res(C函数返回的)是指向Int8数组的指针。自古以来,指针就指向数组的第一个元素。就是这样我们进入ASKII表。 121是字母“ y”的代码。巧合?我不这么认为。一个字符被计数。
此外,根据古老的Sish传统,您可以通过移动指针来遍历数组并获取以下字节:
let p = res+1
print(p.pointee)
这样我们得到116,即代码“ t”。
从理论上讲,如果您知道分配的内存大小,则可以像这样继续进行。并且此内存分配在C代码内部。
在我们的情况下,没有问题,但是在一些更严肃的程序中,您将不得不动手。这是我做的。
解决方案是以良好的旧C结构的形式出现的。
该计划如下:创建一个结构,将倒置的字符串和大小复制到相应的字段中,并返回指向该结构的指针。
struct FlipedStringStructure {
void *result;
int resultSize;
};
让我们这样重写函数:
struct FlipedStringStructure* flipStringToStruct(uint8_t* str, int strlen){
uint8_t* result = malloc(strlen);
int i;
int j=0;
for(i = strlen-1; i>=0; --i){
result[j] = str[i];
j++;
}
struct FlipedStringStructure* structure;
structure = malloc(sizeof(struct FlipedStringStructure));
structure->resultSize=j;
structure->result = malloc(j);
memcpy(structure->result,result,j);
free(result);
return structure;
}
我们注意到我们为结构和字符串分配了内存。
好吧-它仍然是重写挑战。我们跟随我们的双手。
func flip(str:String)->String?{
var array: [UInt8] = Array(str.utf8)
let stringPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: array.count)
stringPointer.initialize(from: &array, count: array.count)
let structPointer = flipStringToStruct(stringPointer, Int32(array.count))
guard structPointer != nil else{return nil}
let tmp = structPointer!.pointee
let res = Data(bytes: tmp.result, count: Int(tmp.resultSize))
let resStr = String(decoding: res, as: UTF8.self)
freeMemmory(tmp.result)
freeSMemmory(structPointer)
return resStr
}
我们仍然使用pointee属性,但是现在我们获得了用C代码创建的结构类型的第一个元素。这个想法的好处是我们可以引用代码C部分中声明的数据类型,而不必进行不必要的强制转换。第一部分已被拆卸。接下来的步骤:获取一个指向用C填充的结构的指针(structPointer)。
我们可以访问此结构的内存。该结构具有数据和数据大小。
您可以将它们称为迅速(通过点)创建的结构的字段。
我们从中收集一个字节数组(数据),并将其解码为String。好吧,别忘了自己清理。我们创建2个函数:
void freeMemmory(void* s){
free(s);
}
void freeSMemmory(struct FlipedStringStructure* s){
free(s);
}
从Swift调用这些函数时,我们会将接收到的指针或结构中的指针作为参数传递给它们。
freeMemmory(tmp.result)
freeSMemmory(structPointer)
瞧-它在书包里!
当然,这种方法没有什么新意,但是它允许您主动使用跨平台功能,并且非常方便。
感谢那些阅读它的人。
链接到git中的项目-这里
EOF