作为一种可与 objective-c 相互调用的语言,swift 也具有一些与 c 语言的类型和特性,如果你的代码有需要,swift 也提供了和常见的 c 代码结构混合编程的编程方式。
基本数据类型
swift 提供了一些和 c 语言的基本类型如char,int,float,double等价的 swift 基本数据类型。然而,这些 swift 的核心基本类型之间并不能隐式的相互转换,如 int。因此,只有你的代码明确要求它们时再使用这些类型,而 int 可以在任何你想使用它的时候使用。
c 类型 | swift 类型 |
---|---|
bool | cbool |
char, signed char | cchar |
unsigned char | cunsignedchar |
short | cshort |
unsigned short | cunsignedshort |
int | cint |
unsigned int | cunsignedint |
long | clong |
unsigned long | cunsignedlong |
long long | clonglong |
unsigned long long | cunsignedlonglong |
wchar_t | cwidechar |
char16_t | cchar16 |
char32_t | cchar32 |
float | cfloat |
double | cdouble |
枚举
swift 引进了用宏ns_enum来标记的任何 c 风格的枚举类型。这意味着无论枚举值是在系统框架还是在自定义的代码中定义的,当他们导入到 swift 时,他们的前缀名称将被截断。例如,看这个 objective-c 枚举:
//objective-c
typedef ns_enum(nsinteger, uitableviewcellstyle) {
uitableviewcellstyledefault,
uitableviewcellstylevalue1,
uitableviewcellstylevalue2,
uitableviewcellstylesubtitle
};
在 swift 中这样来实现:
//swift
enum uitableviewcellstyle: int {
case default
case value1
case value2
case subtitle
}
当您需要指向一个枚举值时,使用以点(.)开头的枚举名称:
//swift
let cellstyle: uitableviewcellstyle = .default
swift 也引进了标有ns_options宏选项。而选项的行为类似于引进的枚举,选项还可以支持一些位操作,如 &,| 和 ~。在 objective-c 中,你用一个空的选项设置标示恒为零(0)。在 swift 中,使用 nil代表没有任何选项。
指针
swift 尽可能避免让您直接访问指针。然而,当您需要直接操作内存的时候,swift 也为您提供了多种指针类型。下面的表使用 type 作为占位符类型名称来表示语法的映射。
对于参数,使用以下映射:
c 句法 | swift 句法 |
---|---|
const void * | cconstvoidpointer |
void * | cmutablevoidpointer |
const type * | cconstpointer |
type * | cmutablepointer |
对于返回类型,变量和参数类型的多层次指针,使用以下映射:
c 句法 | swift 句法 |
---|---|
void * | copaquepointer |
type * | unsafepointer |
对于类(class)类型,使用以下映射:
c 句法 | swift 句法 |
---|---|
type * const * | cconstpointer |
type * __strong * | cmutablepointer |
type ** | autoreleasingunsafepointer |
c 可变指针
当一个函数被声明为接受cmutablepointer
•nil,作为空指针传入
•一个cmutablepointer
•一个操作数是 type 类型的左值的输入输出表达式,作为这个左值的内存地址传入
•一个输入输出 type[] 值,作为一个数组的起始指针传入,并且它的生命周期将在这个调用期间被延长
如果您像这样声明了一个函数:
//swift
func takesamutablepointer(x: cmutablepointer
那么您可以使用以下任何一种方式来调用这个函数:
//swift
var x: float = 0.0
var p: cmutablepointer
var a: float[] = [1.0, 2.0, 3.0]
takesamutablepointer(nil)
takesamutablepointer(p)
takesamutablepointer(&x)
takesamutablepointer(&a)
当函数被声明使用一个cmutablevoidpointer参数,那么这个函数接受任何和cmutablepointer
如果您这样定义了一个函数:
//swift
func takesamutablevoidpointer(x: cmutablevoidpointer) { /* ... */ }
那么您可以使用以下任何一种方式来调用这个函数:
var x: float = 0.0, y: int = 0
var p: cmutablepointer
var a: float[] = [1.0, 2.0, 3.0], b: int = [1, 2, 3]
takesamutablevoidpointer(nil)
takesamutablevoidpointer(p)
takesamutablevoidpointer(q)
takesamutablevoidpointer(&x)
takesamutablevoidpointer(&y)
takesamutablevoidpointer(&a)
takesamutablevoidpointer(&b)
c 常指针
当一个函数被声明为接受cconstpointer
•nil,作为空指针传入
•一个cmutablepointer
•一个操作数是 type 类型的左值的输入输出表达式,作为这个左值的内存地址传入
•一个type[]数组值,作为一个数组的起始指针传入,并且它的生命周期将在这个调用期间被延长
//swift
func takesaconstpointer(x: cconstpointer
那么您可以使用以下任何一种方式来调用这个函数:
//swift
var x: float = 0.0
var p: cconstpointer
takesaconstpointer(nil)
takesaconstpointer(p)
takesaconstpointer(&x)
takesaconstpointer([1.0, 2.0, 3.0])
当函数被声明使用一个cconstvoidpointer参数,那么这个函数接受任何和cconstpointer
//swift 
func takesaconstvoidpointer(x: cconstvoidpointer) { /* ... */ }
那么您可以使用以下任何一种方式来调用这个函数:
//swift
var x: float = 0.0, y: int = 0
var p: cconstpointer
takesaconstvoidpointer(nil)
takesaconstvoidpointer(p)
takesaconstvoidpointer(q)
takesaconstvoidpointer(&x)
takesaconstvoidpointer(&y)
takesaconstvoidpointer([1.0, 2.0, 3.0])
takesaconstvoidpointer([1, 2, 3])
自动释放不安全指针
当一个函数被声明为接受autoreleasingunsafepointer
•nil,作为空指针传入
•一个autoreleasingunsafepointer
•其操作数是原始的,复制到一个临时的没有所有者的缓冲区的一个输入输出表达式,该缓冲区的地址传递给调用,并返回时,缓冲区中的值加载,保存,并重新分配到操作数。
注意:这个列表没有包含数组。
如果您这样定义了一个函数:
//swift
func takesanautoreleasingpointer(x: autoreleasingunsafepointer
那么您可以使用以下任何一种方式来调用这个函数:
//swift
var x: nsdate? = nil
var p: autoreleasingunsafepointer

takesanautoreleasingpointer(nil)
takesanautoreleasingpointer(p)
takesanautoreleasingpointer(&x)
注意:c 语言函数指针没有被 swift 引进。
全局常量
在 c 和 objective-c 语言源文件中定义的全局常量会自动地被 swift 编译引进并做为 swift 的全局常量。
预处理指令
swift 编译器不包含预处理器。取而代之的是,它充分利用了编译时属性,生成配置,和语言特性来完成相同的功能。因此,swift 没有引进预处理指令。
简单宏
在 c 和 objective-c,您通常使用的#define指令定义的一个宏常数,在 swift,您可以使用全局常量来代替。例如:一个全局定义#define fade_animation_duration 0.35,在 swift 可以使用let fade_animation_duration = 0.35来更好的表述。由于简单的用于定义常量的宏会被直接被映射成 swift 全局量,swift 编译器会自动引进在 c 或 objective-c 源文件中定义的简单宏。
复杂宏
在 c 和 objective-c 中使用的复杂宏在 swift 中并没有与之对应的定义。复杂宏是那些不用来定义常量的宏,而是用来定义包含小括号(),函数的宏。您在 c 和 objective-c 使用复杂的宏是用来避免类型检查的限制和相同代码的重复劳动。然而,宏也会产生bug和重构的困难。在 swift 中你可以直接使用函数和泛型来达到同样的效果。因此,在 c 和 objective-c 源文件中定义的复杂宏在 swift 是不能使用的。
编译配置
swift 代码和 objective-c 代码以不同的方式进行条件编译。swift 代码可以根据生成配置的评价配进行有条件的编译。生成配置包括 true 和 false 字面值,命令行标志,和下表中的平台测试函数。您可以使用-d <#flag#>指定命令行标志。
函数 | 有效参数 |
---|---|
os() | osx, ios |
arch() | x86_64, arm, arm64, i386 |
注意:arch(arm) 的生成配置不会为64位 arm 设备返回true,当代码运行在为32位的 ios 模拟器器时,arch(i386) 的生成配置返回true。
一个简单的条件编译需要以下代码格式:
#if build configuration
statements
#else
statements
#endif
一个由零个或多个有效的 swift 语句声明的statements,可以包括表达式,语句和控制流语句。您可以添加额外的构建配置要求,条件编译说明用 && 和 | | 操作符以及 ! 操作符,添加条件控制块用 #elseif:
#if build configuration && !build configuration
statements
#elseif build configuration
statements
#else
statements
#endif
与 c 语言编译器的条件编译相反,swift 条件编译语句必须完全是自包含和语法有效的代码块。这是因为 swift 代码即使没有被编译,也要全部进行语法检查。