Swift编译特性和条件编译

2,322 阅读3分钟

预处理和预编译

Swift与C、C++、Objective-C不同,它没有预处理过程。使用的是预编译来解析和处理源代码-即在编译时处理代码。 预编译包含如下几个功能

  1. 编译特性(attribute)
  2. 编译标志(条件编译)
  3. 检查API的可⽤性

编译特性(attribute)

  • Swift的特性(attribute)与C/C++的 __attribute__ ⾮常类似
  • 修饰对象、函数和类型,指定编译时⾏为。
  • @ 符号开始,后⾯紧跟特性名。
@attribute(args) 
func function() {
} 

下面是一些常用的特性

  1. available
  • 表示在系统平台上的可用性(iOS、macOS、watchOS、tvOS、swift, ⽤ * 代表所有平台)
// MyStruct只能在iOS 14+ macOS 12.0+, Swift 5.0+ 版本使用
@available(swift 5.0) 
@available(iOS 14, macOS 12.0, *) 
struct MyStruct { 
}
  • 哪个版本开始可⽤(introduced),哪个版本开始废弃(deprecated),哪个版本不可⽤(obsoleted)。
/// myTest函数iOS 13开始引⼊, 14开始废弃,15不可用
@available(iOS, introduced: 13, deprecated: 14, obsoleted: 15, message: "The function is deprecated!") 
func myTest() { 
}
  1. discardableResult

修饰带有返回值的方法,表示方法返回值可以丢弃, 不会出现返回值未被使⽤警告

@discardableResult 
func foo(a: Int) -> Int {
    return a + 1 
}
foo(a: 10)
  1. objc
  • 使用@objc 把类、方法、属性暴露给Objective-C
  • Protocol 的方法加上@objc表示optional(非必须实现),
@objc
protocol MyProt {
    // 此方法必须实现
    func method()
    
    // 不是必须实现
    @objc
    optional func foo()
}
  1. autoclosure

将表达式⾃动封装为不带参数的闭包。

func logIfTrue(_ predicate: @autoclosure () -> Bool) {
    if predicate() {
        print(#function)
    }
}
logIfTrue(1 < 2)
  1. convention
  • @convention(swift): 表示Swift闭包,Swift标准函数调用约定
  • @convention(block):相当于OC的block的闭包
  • @convention(c):相当于c函数指针的闭包
/// 作为Objective-C对象使⽤ 
let ref2: @convention(block) (Int) -> Void = 
{(a: Int) -> Void in 
    x -= a 
}
/// C函数没有执⾏上下⽂,因此⽆法捕获局部对象
let ref3: @convention(c) (Int) -> Void = 
{ (a: Int) -> Void in 
    print("a + 1 = \(a + 1)") 
}
  1. escaping

逃逸闭包, 闭包作为函数形参会在稍后执⾏,该闭包的⽣命周期将延伸到函数执行后。

编译器强制你显式的使用 self,从而避免循环引用问题。

  1. inline

表示内联函数, 内联函数的实现直接内嵌在调用处,取代函数调用,提高执行效率。

  • never 表⽰函数何时都不应该被內联。
  • __always 表⽰总是被內联
@inline(never) 
func noinlineFunc() { 
    print("Never inlined!") 
}
@inline(__always) 
func alwaysinlineFunc() { 
    print("always inlined!") 
}

Swift编译器会根据编译上下⽂⾃⾏决定函数是否需要内联

  1. _silgen_name

表示是⼀个遵循C语⾔标准ABI的函数, 用于在Swift中实现标准C函数的功能,

// 声明具有外部连接的C函数CFunc。 
// CFunc函数可以在C代码中无缝调用
@_silgen_name("CFunc") 
func CFunc(_: Int) -> Int {
    return 0
}

这个特性对于Swift的⽣态⼗分重要,Swift的ABI可以与C保持兼容,即可以⽤C的地⽅就能使⽤Swift

编译标志(条件编译)

Swift编译器同C/C++的类似,可以设置编译选项。

-D DEBUG,表示在调试时新增DEBUG编译标志,

使用#if ... #else ... #endif 做条件编译, 没有 #ifdef#ifndef这种形式。

func debug_log(str: String) { 
    #if DEBUG 
        print(str) 
    #endif 
}
debug_log(str: "Hello, world!!")

使⽤ &&、||、! 做联合判断。

#if (DEBUG && !os(iOS)) || arch(x86_64) 
print("Hello, world!") 
#elseif arch(arm64) 
print("Thanks world!") 
#else 
print("Others...") 
#endif

Swift⽀持如下预先定义的条件编译

  1. os()

表⽰操作系统环境。有效参数:macOS、iOS、watchOS、tvOS、Linux、FreeBS

  1. arch()

表⽰处理器环境。有效参数:i386,x86_64,arm,arm64。

  1. swift()

表⽰Swift语⾔版本。⽐如:swift(>=5.0) 表⽰Swift版本从5.0开始起。

检查API的可⽤性

if 与#available联⽤,构成⼀个运⾏时平台检查代码。如果指定的平台以及系统版本成⽴,就执⾏ if 块中的代码

// iOS 10 以后才可以使用这种block定义timer的方法
if #available(iOS 10, *) {
    Timer.scheduledTimer(withTimeInterval:1.0,repeats:false) { 
    (timer: Timer) -> Void in 
        print("timer fired!") 
    } 
} else {
    Timer.scheduledTimer(timeInterval:1.0,target:self,
    selector:#selector(timerHandler(:)),userInfo:nil,repeats:false)
}

#available的用法和参数与@available很相似。