特性

特性给有关声明或类型提供更多的信息。在 Swift 中有两种特性,一种用于声明,另一种用于类型。

通过在 @ 符号后跟一个特性名称和该特性可以接受的实际参数来指定一个特性:

一些接受实际参数的声明特性指定了更多关于它的信息和它们如何应用到特定的声明中。这些特性实际参数写在一对括号里,其格式由它们所属的特性定义。

声明特性

声明特性只能应用于声明中。

available

把这个特性应用到任意声明中,以指出该声明相对于特定平台和操作系统版本的生命周期。

available 特性总是和两个或两个以上用逗号隔开的特性实参列表同时出现。实参列表中的第一个参数是下列平台名称之一:

  • iOS
  • iOSApplicationExtension
  • macOS
  • macOSApplicationExtension
  • watchOS
  • watchOSApplicationExtension
  • tvOS
  • tvOSApplicationExtension

你也可以用星号( * )指明一个声明在上述所有平台中都可用。

其余实参可以按任何顺序出现,它们指定关于声明生命周期的其他信息,包括重要的里程碑。

  • unavailable 实参表示其声明不能用于特定的平台上。
  • introduced 实参表示引入声明的特定平台的最低版本。其格式如下所示:

introduced: version number

version number 由一个或一个以上正整数组成,用小数点隔开。

  • deprecated 实参表示弃用声明的特定平台的最低版本。其格式如下所示:

deprecated: version number

可选的 version number 由一个或一个以上正整数组成,用小数点隔开。不写版本号表示现在弃用了该声明,不给出任何关于该声明何时被弃用的信息。如果你不写版本号,也不要写冒号( : )。

  • obsoleted 实参表示废弃声明的特定平台的最低版本。当一个声明被废弃之后,它就从特定的平台移除了,以后不能再使用。其格式如下所示:

obsoleted: version number

version number 由一个或一个以上正整数组成,用小数点隔开。

  • message 实参用于显示那些,由于使用了被弃用或被作废的声明而编译器显示的警告或错误文本信息。其格式如下所示:

message: message

message 实参由字符串字面量组成。

  • renamed 实参用于提供改了名称的声明的新名字。使用已经改了名称的声明时会发生错误,这时编译器会显示其新名字。格式如下所示:

renamed: new name

new name 由字符串字面量组成。

你可以结合 unavailable 实参和类型别名声明使用 renamed 实参,告诉你代码的使用者,声明已经改名字了。例如,发布一个 framework 或静态库时有一个声明的名称会改变,这是就很有用。

你可以在单个声明中使用多个 available 特性,以指定该声明在不同平台上是否可用。只有当前target的平台和一个属性中指定的平台相同时,编译器才会使用这个 available 特性。

如果一个 available 特性除了一个平台名称实参外只指定一个 introduced 实参,可以使用下面的简化语法:

@available(platform name  version number, *)

available 特性的简化语法允许简洁地表示多个平台的可用性。尽管两种格式功能上是一样的,只要有可能,尽量使用简化语法。

discardableResult

把这个特性用在函数或方法的声明中,当调用一个有返回值的函数或者方法却没有使用返回值时,编译器不会产生警告。

GKInspectable

用这个特性可以把一个自定义的 GameplayKit 组件属性显示到 SpriteKit 编辑器界面中。

objc

把这个特性用到任何可以在 Objective-C 中表示的声明上——例如,非内嵌类,协议,非泛型枚举(原始值类型只能是整数),类和协议的属性、方法(包括 setter 和 getter ),初始化器,反初始化器,下标。 objc 特性告诉编译器,这个声明在 Objective-C 代码中是可用的。

objc 特性标记的类必须继承自一个 Objective-C 中定义的类。如果你把 objc 用到类或协议中,它会隐式地应用于该类或协议中 Objective-C 兼容的成员上。如果一个类继承自另一个带 objc 特性标记或 Objective-C 中定义的类,编译器也会隐式地给这个类添加 objc 特性。标记为 objc 特性的协议不能继承自非 objc 特性的协议。

如果你在一个枚举中使用 objc 特性,枚举名和每个成员名串联起来,作为枚举成员暴露给 Objective-C 代码。成员名首字母大写。例如,一个Swift Planet 枚举成员叫做 venus ,它作为一个叫 PlanetVenus 的成员暴露到Objective-C代码中。

objc 特性可以接受一个特性实参,由一个标识符组成。当你想在 Objective-C 中为 objc 特性标记的实体暴露一个不同的名字时,用这个特性。你可以把这个实参用在命名类,枚举,枚举成员,协议,方法,getter,setter,初始化器。下面的例子把 ExampleClass 中 enabled 属性的getter作为 isEnabled 暴露给 Objective-C 代码,而不仅仅是属性本身的名字。

nonobjc

把这个特性应用到一个方法,属性,下标,或者初始化器的声明中,废除一个隐式 objc 特性 。尽管有可能在 Objective-C 中表示一个声明, nonobjc 特性告诉编译器,使其声明在 Objective-C 代码中不可用。

对于一个标为 objc 特性的类中桥接的方法,你可以使用 nonobjc 特性解决其循环性,并且允许重载标为 objc 特性的类中的方法和初始化器。

一个标记为 nonobjc 特性的方法不能重写标为 objc 特性的方法。但是,一个标记为 objc 特性的方法可以重写一个标为 nonobjc 特性的方法。同样,一个标为 nonobjc 特性的方法不能满足一个标为 objc 特性方法的协议需求。

NSApplicationMain

将这个特性应用于一个类中,来指明它是应用的委托。用这个特性等同于调用 NSApplicationMain(_:_:) 函数。

如果你使用这个特性,需要提供一个 main.swift 文件,在其代码的最上层调用如下 NSApplicationMain(_:_:) 函数:

NSCopying

这个特性用于一个类的可变存储属性中。这个特性让属性值(由 copyWithZone(_:) 方法返回,而不是属性本身的值)的拷贝合成属性的setter。属性的类型必须遵循 NSCopying 协议。

从某种程度上来说, NSCopying 特性的行为类似 Objective-C 中的 copy 属性特性。

NSManaged

把这个特性应用于一个继承自 NSManagedObject 的类的实例方法或可变存储属性中,以指明 Core Data 会在运行时根据相关的实体描述动态提供它的实现。对于标记为 NSManaged 特性的属性,Core Data 还会在运行时提供存储。用这个特性还隐含 objc 特性。

testable

用这个特性 import 那些编译时开启了测试功能的模块中的声明,就像他们被声明为 public 访问级别一样去访问任何标记为 internal 访问级别的实体。测试还可以访问那些标记为 internal 或 public 访问级别的类和类成员,就像他们被声明为 open 访问级别一样。

UIApplicationMain

给一个类用这个特性,以指出它是应用的委托。用这个特性等同于用调用 UIApplicationMain 函数并把这个类名作为委托类的名字传进函数中。

如果你不用这个特性,需要提供一个 main.swift 文件,在其代码的最上层调用 UIApplicationMain(_:_:_:) 函数。例如,如果你的app用了一个 UIApplication 的自定义子类作为它的主要类,调用 UIApplicationMain(_:_:_:) 函数,而不是使用这个特性。

通过Interface Builder使用声明特性

Interface Builder 特性是用于 Interface Builder 和 Xcode 同步的声明特性。Swift 提供了下列 Interface Builde r特性: IBAction , IBOutlet , IBDesignable ,和 IBInspectable 。这些特性概念上和 Objective-C 中的相同。

你可以把 IBOutlet 和 IBInspectable 特性应用于一个类的属性声明中。把 IBAction 特性用于一个类的方法声明,把 IBDesignable 特性用于类的声明。

IBAction 和 IBOutlet 特性都隐含 objc 特性。

类型特性

类型特性只能用于类型中。

autoclosure

这个特性用于,通过自动包装没有实参的表达式来延迟对表达式的求值。这个特性用于一个方法或函数声明的形参类型中,该形参是一个函数类型,这个函数类型不接受实参并且返回一个表达式的类型的值。有关如何使用 autoclosure 特性的示例,参见自动闭包函数类型

convention

把这个特性应用于一个函数的类型以指明它的调用约定。

convention 特性总是和下列特性实参中的一个同时出现:

  • swift 实参用于指明一个 Swift 函数引用。在 Swift 中,这是函数值的标准调用约定。
  • block 实参用于指明一个 Objective-C 兼容的闭包引用。函数值表示为对闭包对象的一个引用,它是一个兼容 id 的、在其中嵌入它的调用函数的 Objective-C 对象。调用函数用 C 调用约定。
  • c 实参用于指明一个 C 函数引用。函数值不携带上下文并且使用 C 调用确定

C 函数调用约定的函数可以当做 Objective-C 闭包调用约定的函数使用, Objective-C 闭包调用约定的函数可以当做 Swift 函数调用约定的函数使用。但是,只有非泛型全局函数,和局部函数或不捕获任何局部变量的闭包,可以当做一个 C 函数调用约定的函数使用。

escaping

将这个特性应用到一个方法或函数声明的形参类型中,以指明可以存储该形参值用于稍后执行。这意味着允许那个值超过调用它的范围而存在。 escaping 类型特性的函数类型形参需要为属性或方法显式使用 self. 。有关如何使用 explicit 特性,参见逃逸闭包

特性的语法

attribute → @ attribute-name attribute-argument-clauseopt

attribute-name → identifier

attribute-argument-clause → (balanced-tokensopt)

attributes → attribute­attributesopt

balanced-tokens  balanced-token ­balanced-tokens­opt

balanced-token @ (­balanced-tokens­opt­)

balanced-token  balanced-tokens­opt­

balanced-token  balanced-tokens­opt­}

balanced-token → Any identifier, keyword, literal, or operator

balanced-token  Any punctuation except , or }­