Cwift
用于 C-Swift 互操作的条件 clang 属性。
用于跨平台头文件的 Clang Swift 属性的宏,在非 Apple 平台上将展开为空。
使用 pod 'Cwift'
通过 Cocoapods 进行安装。
示例项目在此处
如何使用
Cwift 的目的是能够利用 clang 的 Swift 特定属性而无需导入 Foundation。一个常见的用例是您希望在 C++ 和 Swift 代码中使用相同的枚举。您不能在非苹果代码中使用 NS_ENUM,因为没有导入 Foundation 的方法。Cwift 通过条件地直接添加属性来处理这种情况。
// MyCFile.h
typedef enum CWIFT_ENUM Region {
RegionNorth,
RegionEast,
RegionSouth,
RegionWest
} Region;
在 C++ 中,`CWIFT_ENUM` 不会展开为任何内容,使其成为一个常规的枚举。然而,当将其导入到 Swift 中时,您将能够使用点语法。
///////////////// MySwiftFile.swift /////////////////
var myregion = Region.north
myRegion = .west
这也适用于选项集。
///////////////// MyCFile.h /////////////////
typedef enum CWIFT_OPTIONS Characteristic {
CharacteristicCool = 1 << 0,
CharacteristicSmart = 2 << 0,
CharacteristicFunny = 3 << 0
} Characteristic;
特征是 C/C++ 中的常规位掩码,但导入 Swift 作为选项集。
///////////////// MySwiftFile.swift /////////////////
var characteristics: Characteristic = [.smart, .funny]
if !characteristics.contains(.cool) {
characteristics.insert(.cool)
}
一个非常实用的属性是swift_newtype(struct),它通过CWIFT_TYPE条件性地添加。这允许你在C代码库中创建强类型,而当使用一些更模糊的数据类型(如void*)时非常有用。具体的类型使得在Swift中可以进行扩展,这在你无法直接导入类型时很有用,例如在C++中。强类型还使得使用CWIFT_NAME成为可能,这将函数与类型关联,以便使用点符号。
///////////////// MyCppFile.hpp /////////////////
namespace census_model {
class person {
public:
int age;
Region region;
};
}
Person
将用于指向census_model::person
。在C/C++中,这有助于将我们的包装函数与它们包装的类型关联起来。
///////////////// MyCFile.h /////////////////
typedef void * Person CWIFT_TYPE;
Person PersonCreate(int age, Region region) CWIFT_NAME(Person.init(age:region:));
int PersonGetAge(Person person) CWIFT_NAME(getter:Person.age(self:));
void PersonSetAge(Person person, int age) CWIFT_NAME(setter:Person.age(self:newValue:));
Person
使用CWIFT_TYPE
条件性地添加Clang的swift_newtype(struct)属性。在Swift中,它作为一个离散类型导入,与void *
不可互换。由于它是一个类型,可以将其扩展到Swift中,并可以从C声明中扩展使用CWIFT_NAME
。
这是在Swift中调用这三个函数的方式
///////////////// MySwiftFile.swift /////////////////
guard var person = Person(age: 20, region: .north) else { fatalError() }
person.age += 10
没有CWIFT_NAME,调用C代码如下
guard var person = PersonCreate(age: 20, region: .north) else { fatalError() }
PersonSetAge(person, PersonGetAge(person) + 10)
在C/C++中Person是一个void *
。在你的包装实现中将其转换为Person -> census_model::person。
///////////////// MyCFile.c /////////////////
Person PersonCreate(int age, Region region) {
return (Person) new census_model::person {
.age = age,
.region = region
};
}
int PersonGetAge(Person person) {
return ((census_model::person *)person)->age;
}
void PersonSetAge(Person person, int age) {
((census_model::person *)person)->age = age;
}
版权所有(C)2019 David O'Neill
特此授予任何获得本软件及其相关文档副本(统称为“软件”)的任何人处理该软件的权利,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本的权利,并允许软件提供方的任何人为此目的对其进行操作,前提是以下条件
上述版权声明和本许可协议应包含在本软件的所有副本或主要部分中。
软件按“原样”提供,没有任何形式的明示或暗示的保证,包括但不限于适销性、适用于特定目的和无侵权的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任承担责任,无论这些责任是出于合同、侵权或其他原因,是否源于、来源于或与本软件或其使用或其他买卖有关。