在 Swift 中有兩種特性,分別用于修飾聲明和類型。特性提供了有關(guān)聲明和類型的更多信息。例如,使用 discardableResult
特性聲明的函數(shù),表明該函數(shù)雖然有返回值,但如果沒(méi)有使用該返回值,編譯器不會(huì)產(chǎn)生警告。
您可以通過(guò)以下方式指定一個(gè)特性,通過(guò)符號(hào) @
后跟特性的名稱和特性接收的任何參數(shù):
@特性名
@特性名
(特性參數(shù)
)
有些聲明特性通過(guò)接收參數(shù)來(lái)指定特性的更多信息以及它是如何修飾某個(gè)特定的聲明的。這些特性的參數(shù)寫在圓括號(hào)內(nèi),它們的格式由它們所屬的特性來(lái)定義。
聲明特性只能應(yīng)用于聲明。
available
將 available
特性用于聲明時(shí),表示該聲明的生命周期是相對(duì)于特定的平臺(tái)和操作系統(tǒng)版本。
available
特性經(jīng)常與參數(shù)列表一同出現(xiàn),該參數(shù)列表至少有兩個(gè)特性參數(shù),參數(shù)之間由逗號(hào)分隔。這些參數(shù)由以下這些平臺(tái)名字中的一個(gè)起頭:
iOS
iOSApplicationExtension
macOS
macOSApplicationExtension
watchOS
watchOSApplicationExtension
tvOS
tvOSApplicationExtension
swift
當(dāng)然,你也可以用一個(gè)星號(hào)(*
)來(lái)表示上面提到的所有平臺(tái)。指定 Swift 版本的 available
特性參數(shù),不能使用星號(hào)表示。
其余的參數(shù),可以按照任何順序出現(xiàn),并且可以添加關(guān)于聲明生命周期的附加信息,包括重要事件。
unavailable
參數(shù)表示該聲明在指定的平臺(tái)上是無(wú)效的。當(dāng)指定 Swift 版本可用性時(shí)不可使用該參數(shù)。introduced
參數(shù)表示指定平臺(tái)從哪一版本開(kāi)始引入該聲明。格式如下:introduced
: 版本號(hào)
版本號(hào)由一至三個(gè)正整數(shù)構(gòu)成,由句點(diǎn)分隔的。
deprecated
參數(shù)表示指定平臺(tái)從哪一版本開(kāi)始棄用該聲明。格式如下:deprecated
: 版本號(hào)
可選的版本號(hào)由一個(gè)或多個(gè)正整數(shù)構(gòu)成,由句點(diǎn)分隔的。省略版本號(hào)表示該聲明目前已棄用,而不提供有關(guān)棄用發(fā)生時(shí)間的任何信息。如果你省略了版本號(hào),冒號(hào)(:
)也可省略。
obsoleted
參數(shù)表示指定平臺(tái)或語(yǔ)言從哪一版本開(kāi)始廢棄該聲明。當(dāng)一個(gè)聲明被廢棄后,它就從平臺(tái)或語(yǔ)言中移除,不能再被使用。格式如下:obsoleted
: 版本號(hào)
版本號(hào)由一至三個(gè)正整數(shù)構(gòu)成,由句點(diǎn)分隔的。
message
參數(shù)用來(lái)提供文本信息。當(dāng)使用被棄用或者被廢棄的聲明時(shí),編譯器會(huì)拋出該信息作為警告或錯(cuò)誤。格式如下:message
: 信息內(nèi)容
信息內(nèi)容由一個(gè)字符串構(gòu)成。
renamed
參數(shù)用來(lái)提供文本信息,用以表示被重命名聲明的新名字。當(dāng)使用聲明的舊名字時(shí),編譯器會(huì)報(bào)錯(cuò)并提示新名字。格式如下:renamed
: 新名字
新名字由一個(gè)字符串構(gòu)成。
你可以將帶有 renamed
和 unavailable
參數(shù)的 available
特性應(yīng)用于類型別名聲明,如下所示,來(lái)表明框架和庫(kù)發(fā)行版本之間的聲明名稱已經(jīng)被更改。這個(gè)組合會(huì)導(dǎo)致聲明已重命名的編譯時(shí)錯(cuò)誤。
// 首發(fā)版本
protocol MyProtocol {
// 這里是協(xié)議定義
}
// 后續(xù)版本重命名了 MyProtocol
protocol MyRenamedProtocol {
// 這里是協(xié)議定義
}
@available(*, unavailable, renamed:"MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
你可以在某個(gè)聲明上使用多個(gè) available
特性,以指定該聲明在不同平臺(tái)和 Swift 版本上的可用性。如果當(dāng)前目標(biāo)與 available
特性中指定的平臺(tái)或語(yǔ)言版本不匹配時(shí),該聲明將會(huì)被忽略。如果你使用了多個(gè) available
特性,則最終效果是平臺(tái)和 Swift 可用性的組合。
如果 available
特性除了平臺(tái)名稱或者語(yǔ)言版本參數(shù)之外,只指定了一個(gè) introduced
參數(shù),那么可以使用以下簡(jiǎn)寫語(yǔ)法代替:
@available(平臺(tái)名稱
版本號(hào)
, *)
@available(swift 版本號(hào)
)
available
特性的簡(jiǎn)寫語(yǔ)法簡(jiǎn)潔的表示了多個(gè)平臺(tái)的可用性。盡管這兩種形式在功能上是相同的,但請(qǐng)盡可能地使用簡(jiǎn)寫語(yǔ)法形式。
@available(iOS 10.0, macOS 10.12, *)
class MyClass {
// 這里是類定義
}
當(dāng)需要同時(shí)指定 Swift 版本和平臺(tái)可用性,需要使用一個(gè)單獨(dú)的 available
特性來(lái)指明 Swift 版本,以及一個(gè)或者多個(gè) available
特性來(lái)聲明平臺(tái)可用性。
@available(swift 3.0.2)
@available(macOS 10.12, *)
struct MyStruct {
// 這里是結(jié)構(gòu)體定義
}
discardableResult
該特性用于的函數(shù)或方法聲明,以抑制編譯器中函數(shù)或方法被調(diào)用而其返回值沒(méi)有被使用時(shí)的警告。
dynamicCallable
該特性用于類、結(jié)構(gòu)體、枚舉或協(xié)議,以將該類型的實(shí)例視為可調(diào)用的函數(shù)。該類型必須實(shí)現(xiàn) dynamicallyCall(withArguments:)
、dynamicallyCall(withKeywordArguments:)
方法之一,或兩者同時(shí)實(shí)現(xiàn)。
你可以調(diào)用 dynamicCallable
特性的實(shí)例,就像是調(diào)用一個(gè)任意數(shù)量參數(shù)的函數(shù)。
@dynamicCallable
struct TelephoneExchange {
func dynamicallyCall(withArguments phoneNumber: [Int]) {
if phoneNumber == [4, 1, 1] {
print("Get Swift help on forums.swift.org")
} else {
print("Unrecognized number")
}
}
}
let dial = TelephoneExchange()
// 使用動(dòng)態(tài)方法調(diào)用
dial(4, 1, 1)
// 打印“Get Swift help on forums.swift.org”
dial(8, 6, 7, 5, 3, 0, 9)
// 打印“Unrecognized number”
// 直接調(diào)用底層方法
dial.dynamicallyCall(withArguments: [4, 1, 1])
dynamicallyCall(withArguments:)
方法的聲明必須至少有一個(gè)參數(shù)遵循 ExpressibleByArrayLiteral
協(xié)議,如 [Int]
,而返回值類型可以是任意類型。
如果實(shí)現(xiàn) dynamicallyCall(withKeywordArguments:)
方法,則可以在動(dòng)態(tài)方法調(diào)用中包含標(biāo)簽。
@dynamicCallable
struct Repeater {
func dynamicallyCall(withKeywordArguments pairs: KeyValuePairs<String, Int>) -> String {
return pairs
.map { label, count in
repeatElement(label, count: count).joined(separator: " ")
}
.joined(separator: "\n")
}
}
let repeatLabels = Repeater()
print(repeatLabels(a: 1, b: 2, c: 3, b: 2, a: 1))
// a
// b b
// c c c
// b b
// a
dynamicallyCall(withKeywordArguments:)
方法聲明必須只有一個(gè)遵循 ExpressibleByDictionaryLiteral
協(xié)議的參數(shù),返回值可以任意類型。參數(shù)的 Key
必須遵循 ExpressibleByStringLiteral
協(xié)議。上述的示例使用 KeyValuePairs
作為參數(shù)類型,以便調(diào)用者可以傳入重復(fù)的參數(shù)標(biāo)簽,a
和 b
在調(diào)用 repeat
中多次使用。
如果你同時(shí)實(shí)現(xiàn)兩種 dynamicallyCall
方法,則當(dāng)在方法調(diào)用中包含關(guān)鍵字參數(shù)時(shí),會(huì)調(diào)用 dynamicallyCall(withKeywordArguments:)
方法,否則調(diào)用 dynamicallyCall(withArguments:)
方法。
你只能調(diào)用參數(shù)和返回值與 dynamicallyCall
方法實(shí)現(xiàn)匹配的動(dòng)態(tài)調(diào)用實(shí)例。在下面示例的調(diào)用無(wú)法編譯,因?yàn)槠?dynamicallyCall(withArguments:)
實(shí)現(xiàn)不接受 KeyValuePairs<String, String>
參數(shù)。
repeatLabels(a: "four") // Error
dynamicMemberLookup
該特性用于類、結(jié)構(gòu)體、枚舉或協(xié)議,讓其能在運(yùn)行時(shí)查找成員。該類型必須實(shí)現(xiàn) subscript(dynamicMemberLookup:)
下標(biāo)。
在顯式成員表達(dá)式中,如果指定成員沒(méi)有相應(yīng)的聲明,則該表達(dá)式被理解為對(duì)該類型的 subscript(dynamicMemberLookup:)
下標(biāo)調(diào)用,將有關(guān)該成員的信息作為參數(shù)傳遞。下標(biāo)接收參數(shù)既可以是鍵路徑,也可以是成員名稱字符串;如果你同時(shí)實(shí)現(xiàn)這兩種方式的下標(biāo)調(diào)用,那么以鍵路徑參數(shù)方式為準(zhǔn)。
subscript(dynamicMemberLookup:)
實(shí)現(xiàn)允許接收 KeyPath
,WritableKeyPath
或 ReferenceWritableKeyPath
類型的鍵路徑參數(shù)。它可以使用遵循 ExpressibleByStringLiteral
協(xié)議的類型作為參數(shù)來(lái)接受成員名 -- 通常情況下是 String
。下標(biāo)返回值類型可以為任意類型。
按成員名進(jìn)行的動(dòng)態(tài)成員查找可用于圍繞編譯時(shí)無(wú)法進(jìn)行類型檢查的數(shù)據(jù)創(chuàng)建包裝類型,例如在將其他語(yǔ)言的數(shù)據(jù)橋接到 Swift
時(shí)。例如:
@dynamicMemberLookup
struct DynamicStruct {
let dictionary = ["someDynamicMember": 325,
"someOtherMember": 787]
subscript(dynamicMember member: String) -> Int {
return dictionary[member] ?? 1054
}
}
let s = DynamicStruct()
// 使用動(dòng)態(tài)成員查找
let dynamic = s.someDynamicMember
print(dynamic)
// 打印“325”
// 直接調(diào)用底層下標(biāo)
let equivalent = s[dynamicMember: "someDynamicMember"]
print(dynamic == equivalent)
// 打印“true”
根據(jù)鍵路徑來(lái)動(dòng)態(tài)地查找成員,可用于創(chuàng)建一個(gè)包裹數(shù)據(jù)的包裝類型,該類型支持在編譯時(shí)期進(jìn)行類型檢查。例如:
struct Point { var x, y: Int }
@dynamicMemberLookup
struct PassthroughWrapper<Value> {
var value: Value
subscript<T>(dynamicMember member: KeyPath<Value, T>) -> T {
get { return value[keyPath: member] }
}
}
let point = Point(x: 381, y: 431)
let wrapper = PassthroughWrapper(value: point)
print(wrapper.x)
frozen
針對(duì)枚舉或者結(jié)構(gòu)體的聲明使用該特性,可以限制你對(duì)該類型的修改。它只有在編譯迭代庫(kù)時(shí)被允許使用。未來(lái)版本的庫(kù)不能通過(guò)添加、刪除或重新排序枚舉的 case 或結(jié)構(gòu)的存儲(chǔ)實(shí)例屬性來(lái)更改聲明。在未凍結(jié)的類型上,這些操作都是允許的,但是他們破壞了凍結(jié)類型的 ABI 兼容性。
注意
當(dāng)編譯器不處于迭代庫(kù)的模式,所有的結(jié)構(gòu)體和枚舉都是隱性凍結(jié),并且你不能使用該特性。
在迭代庫(kù)的模式中,與未凍結(jié)結(jié)構(gòu)體和枚舉的成員進(jìn)行交互的代碼在被編譯時(shí),允許它在不重新編譯的情況下繼續(xù)工作,即使在新版本的庫(kù)中添加、刪除或重新排序該類型的成員。編譯器用類似運(yùn)行時(shí)查找信息和添加間接層的技術(shù)使之可能。將一個(gè)枚舉或者結(jié)構(gòu)體標(biāo)記為凍結(jié)將以放棄這種靈活性為代價(jià)來(lái)獲取性能上的提升:未來(lái)版本的庫(kù)只能對(duì)類型進(jìn)行有限的更改,但編譯器可以對(duì)與類型成員交互的代碼進(jìn)行額外的優(yōu)化。
使用凍結(jié)類型,結(jié)構(gòu)體存儲(chǔ)屬性的類型以及枚舉 case 的關(guān)聯(lián)值必須是 public
或使用 usablefrominline
特性標(biāo)記。凍結(jié)結(jié)構(gòu)體的屬性不能有屬性觀察器,為存儲(chǔ)實(shí)例屬性提供初始值的表達(dá)式必須遵循與 inlinable
函數(shù)相同的限制,如 inlinable
中所述。
要在命令行上啟用迭代庫(kù)模式,請(qǐng)將 -enable-library-evolution
選項(xiàng)傳遞給 Swift 編譯器。要在 Xcode 中支持它,則將生成設(shè)置 “Build Libraries for Distribution”(BUILD_LIBRARY_FOR_DISTRIBUTION
)設(shè)置為 Yes,詳情查看 Xcode 幫助文檔
。
針對(duì)凍結(jié)枚舉的 switch 語(yǔ)法,不需要 default
case,就像 對(duì)未來(lái)枚舉的 case 進(jìn)行 switch
。在針對(duì)凍結(jié)枚舉使用 switch 語(yǔ)法時(shí)包含 default
或 @unknown default
case 將生成警告,因?yàn)樵摯a永遠(yuǎn)不會(huì)執(zhí)行。
GKInspectable
應(yīng)用此特性可將自定義 GameplayKit 組件屬性公開(kāi)到 SpriteKit 編輯器 UI。應(yīng)用此特性同時(shí)表示應(yīng)用了 objc
特性。
inlinable
該特性用于函數(shù)、方法、計(jì)算屬性、下標(biāo)、便利構(gòu)造器或析構(gòu)器的聲明,以將該聲明的實(shí)現(xiàn)公開(kāi)為模塊公開(kāi)接口的一部分。編譯器允許在調(diào)用處把 inlinable
標(biāo)記的符號(hào)替換為符號(hào)實(shí)現(xiàn)的副本。
內(nèi)聯(lián)代碼可以與任意模塊中 public
訪問(wèn)級(jí)別的符號(hào)進(jìn)行交互,同時(shí)可以與在相同模塊中標(biāo)記 usableFromInline
特性的 internal
訪問(wèn)級(jí)別的符號(hào)進(jìn)行交互。內(nèi)聯(lián)代碼不能與 private
或 fileprivate
級(jí)別的符號(hào)進(jìn)行交互。
該特性不能用于嵌套在函數(shù)內(nèi)的聲明,也不能用于 fileprivate
或 private
訪問(wèn)級(jí)別的聲明。在內(nèi)聯(lián)函數(shù)內(nèi)定義的函數(shù)和閉包都是隱式內(nèi)聯(lián)的,即使他們不能標(biāo)記該特性。
nonobjc
針對(duì)方法、屬性、下標(biāo)、或構(gòu)造器的聲明使用該特性將覆蓋隱式的 objc
特性。nonobjc
特性告訴編譯器該聲明不能在 Objective-C 代碼中使用,即便它能在 Objective-C 中表示。
該特性用在擴(kuò)展中,與在沒(méi)有明確標(biāo)記為 objc
特性的擴(kuò)展中給每個(gè)成員添加該特性具有相同效果。
可以使用 nonobjc
特性解決標(biāo)有 objc
的類中橋接方法的循環(huán)問(wèn)題,該特性還允許對(duì)標(biāo)有 objc
的類中的構(gòu)造器和方法進(jìn)行重載。
標(biāo)有 nonobjc
特性的方法不能重寫標(biāo)有 objc
特性的方法。然而,標(biāo)有 objc
特性的方法可以重寫標(biāo)有 nonobjc
特性的方法。同樣,標(biāo)有 nonobjc
特性的方法不能滿足標(biāo)有 @objc
特性的協(xié)議中的方法要求。
NSApplicationMain
在類上使用該特性表示該類是應(yīng)用程序委托類。使用該特性與調(diào)用 NSApplicationMain(_:_:)
函數(shù)的效果相同。
如果你不想使用這個(gè)特性,可以提供一個(gè) main.swift
文件,并在代碼頂層調(diào)用 NSApplicationMain(_:_:)
函數(shù),如下所示:
import AppKit
NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv)
NSCopying
該特性用于修飾一個(gè)類的存儲(chǔ)型變量屬性。該特性將使屬性的設(shè)值方法使用傳入值的副本
進(jìn)行賦值,這個(gè)值由傳入值的 copyWithZone(_:)
方法返回,而不是傳入值本身。該屬性的類型必需符合 NSCopying
協(xié)議。
NSCopying
特性的行為與 Objective-C 中的 copy
屬性特性相似。
NSManaged
該特性用于修飾 NSManagedObject
子類中的實(shí)例方法或存儲(chǔ)型變量屬性,表明它們的實(shí)現(xiàn)由 Core Data
在運(yùn)行時(shí)基于相關(guān)實(shí)體描述動(dòng)態(tài)提供。對(duì)于標(biāo)記了 NSManaged
特性的屬性,Core Data
也會(huì)在運(yùn)行時(shí)為其提供存儲(chǔ)。應(yīng)用這個(gè)特性也意味著 objc
特性。
objc
該特性用于修飾任何可以在 Objective-C 中表示的聲明。比如,非嵌套類、協(xié)議、非泛型枚舉(僅限原始值為整型的枚舉)、類的屬性和方法(包括存取方法)、協(xié)議以及協(xié)議中的可選成員、構(gòu)造器以及下標(biāo)運(yùn)算符。objc
特性告訴編譯器這個(gè)聲明可以在 Objective-C 代碼中使用。
該特性用在擴(kuò)展中,與在沒(méi)有明確標(biāo)記為 nonobjc
特性的擴(kuò)展中給每個(gè)成員添加該特性具有相同效果。
編譯器隱式地將 objc
特性添加到 Objective-C 中定義的任何類的子類。但是,子類不能是泛型的,并且不能繼承于任何泛型類。你可以將 objc
特性顯式添加到滿足這些條件的子類,來(lái)指定其 Objective-C 名稱,如下所述。添加了 objc
的協(xié)議不能繼承于沒(méi)有此特性的協(xié)議。
在以下情況中同樣會(huì)隱式的添加 objc
特性:
objc
特性,且重寫為子類的聲明。objc
特性協(xié)議的聲明。IBAction
、IBSegueAction
、IBOutlet
、IBDesignable
、IBInspectable
、NSManaged
或 GKInspectable
特性的聲明。如果你將 objc
特性應(yīng)用于枚舉,每一個(gè)枚舉 case 都會(huì)以枚舉名稱和 case 名稱組合的方式暴露在 Objective-C 代碼中。實(shí)例名稱的首字母大寫。例如,在 Swift 枚舉類型 Planet
中有一個(gè)名為 Venus
的 case,該 case 暴露在 Objective-C 代碼中時(shí)叫做 PlanetVenus
。
objc
特性可以接受一個(gè)可選的特性參數(shù),由標(biāo)識(shí)符構(gòu)成。當(dāng)你想把 objc
所修飾的實(shí)體以一個(gè)不同的名字暴露給 Objective-C 時(shí),你就可以使用這個(gè)特性參數(shù)。你可以使用這個(gè)參數(shù)來(lái)命名類、枚舉類型、枚舉 case、協(xié)議、方法、存取方法以及構(gòu)造器。如果你要指定類、協(xié)議或枚舉在 Objective-C 下的名稱,請(qǐng)?jiān)诿Q上包含三個(gè)字母的前綴,就像 Objective-C 編程 中的 約定描述的一樣。下面的例子把 ExampleClass
中的 enabled
屬性的取值方法暴露給 Objective-C,名字是 isEnabled
,而不是它原來(lái)的屬性名。
class ExampleClass: NSObject {
@objc var enabled: Bool {
@objc(isEnabled) get {
// 返回適當(dāng)?shù)闹?/span>
}
}
}
objcMembers
該特性用于類聲明,以將 objc
特性應(yīng)用于該類、擴(kuò)展、子類以及子類的擴(kuò)展的所有 Objective-C 兼容成員。
大多數(shù)代碼應(yīng)該使用 objc
特性,以暴露所需的聲明。如果需要暴露多個(gè)聲明,可以將其分組到添加 objc
特性的擴(kuò)展中。objcMembers
特性為大量使用 Objective-C 運(yùn)行時(shí)的內(nèi)省工具的庫(kù)提供了便利。添加不必要的 objc
特性會(huì)增加二進(jìn)制體積并影響性能。
propertyWrapper
在類、結(jié)構(gòu)體或者枚舉的聲明時(shí)使用該特性,可以讓其成為一個(gè)屬性包裝器。如果將該特性應(yīng)用在一個(gè)類型上,將會(huì)創(chuàng)建一個(gè)與該類型同名的自定義特性。將這個(gè)新的特性用于類、結(jié)構(gòu)體、枚舉的屬性,則可以通過(guò)包裝器的實(shí)例封裝對(duì)該屬性的訪問(wèn)。局部和全局變量不能使用屬性包裝器。
包裝器必須定義一個(gè) wrappedValue
實(shí)例屬性。該屬性 wrapped value 是該屬性存取方法暴露的值。大多數(shù)時(shí)候,wrappedValue
是一個(gè)計(jì)算屬性,但它可以是一個(gè)存儲(chǔ)屬性。包裝器負(fù)責(zé)定義和管理其包裝值所需的任何底層存儲(chǔ)。編譯器通過(guò)在包裝屬性的名稱前加下劃線(_
)來(lái)為包裝器的實(shí)例提供同步存儲(chǔ)。例如,someProperty
的包裝器存儲(chǔ)為 _someProperty
。包裝器的同步存儲(chǔ)具有 private
的訪問(wèn)控制級(jí)別。
擁有屬性包裝器的屬性可以包含 willSet
和 didSet
閉包,但是不能重寫編譯器合成的 get
和 set
閉包。
Swift 為屬性包裝器的構(gòu)造函數(shù)提供了兩種形式的語(yǔ)法糖??梢栽诎b值的定義中使用賦值語(yǔ)法,將賦值語(yǔ)句右側(cè)的表達(dá)式作為值傳遞給屬性包裝器構(gòu)造函數(shù)中的 wrappedValue
參數(shù)。同樣的,你也可以為包裝器提供一些參數(shù),這些參數(shù)將會(huì)傳遞給包裝器的構(gòu)造函數(shù)。就像下面的例子,SomeStruct
中,定義 SomeWrapper
的地方各自調(diào)用了對(duì)應(yīng)的構(gòu)造函數(shù)。
@propertyWrapper
struct SomeWrapper {
var wrappedValue: Int
var someValue: Double
init() {
self.wrappedValue = 100
self.someValue = 12.3
}
init(wrappedValue: Int) {
self.wrappedValue = wrappedValue
self.someValue = 45.6
}
init(wrappedValue value: Int, custom: Double) {
self.wrappedValue = value
self.someValue = custom
}
}
struct SomeStruct {
// 使用 init()
@SomeWrapper var a: Int
// 使用 init(wrappedValue:)
@SomeWrapper var b = 10
// 兩個(gè)都是使用 init(wrappedValue:custom:)
@SomeWrapper(custom: 98.7) var c = 30
@SomeWrapper(wrappedValue: 30, custom: 98.7) var d
}
屬性包裝器中 projected value 是它可以用來(lái)暴露額外功能的第二個(gè)值。屬性包裝器的作者負(fù)責(zé)確認(rèn)其映射值的含義并定義公開(kāi)映射值的接口。若要通過(guò)屬性包裝器來(lái)映射值,請(qǐng)?jiān)诎b器的類型上定義 projectedValue
實(shí)例屬性。編譯器通過(guò)在包裝屬性的名稱前面加上美元符號(hào)($
)來(lái)合成映射值的標(biāo)識(shí)符。例如,someProperty
的映射值是 $someProperty
。映射值具有與原始包裝屬性相同的訪問(wèn)控制級(jí)別。
@propertyWrapper
struct WrapperWithProjection {
var wrappedValue: Int
var projectedValue: SomeProjection {
return SomeProjection(wrapper: self)
}
}
struct SomeProjection {
var wrapper: WrapperWithProjection
}
struct SomeStruct {
@WrapperWithProjection var x = 123
}
let s = SomeStruct()
s.x // Int value
s.$x // SomeProjection value
s.$x.wrapper // WrapperWithProjection value
requires-stored-property-inits
該特性用于類聲明,以要求類中所有存儲(chǔ)屬性提供默認(rèn)值作為其定義的一部分。對(duì)于從中繼承的任何類都推斷出 NSManagedObject
特性。
testable
將此特性應(yīng)用于 import
聲明以導(dǎo)入該模塊,并更改其訪問(wèn)控制以簡(jiǎn)化對(duì)該模塊代碼的測(cè)試。這樣就能訪問(wèn)被導(dǎo)入模塊中的任何標(biāo)有 internal
訪問(wèn)級(jí)別修飾符的實(shí)體,猶如它們被標(biāo)記了 public
訪問(wèn)級(jí)別修飾符。測(cè)試也可以訪問(wèn)使用 internal
或者 public
訪問(wèn)級(jí)別修飾符標(biāo)記的類和類成員,就像它們是 open
訪問(wèn)修飾符聲明的。被導(dǎo)入的模塊必須以允許測(cè)試的方式編譯。
UIApplicationMain
在類上使用該特性表示該類是應(yīng)用程序委托類。使用該特性與調(diào)用 UIApplicationMain
函數(shù)并且把該類的名字作為委托類的名字傳遞給函數(shù)的效果相同。
如果你不想使用這個(gè)特性,可以提供一個(gè) main.swift
文件,并在代碼頂層調(diào)用 UIApplicationMain(_:_:_:_:)
函數(shù)。比如,如果你的應(yīng)用程序使用一個(gè)繼承于 UIApplication
的自定義子類作為主要類,你可以調(diào)用 UIApplicationMain(_:_:_:_:)
函數(shù)而不是使用該特性。
usableFromInline
該特性用于函數(shù)、方法、計(jì)算屬性、下標(biāo)、構(gòu)造器或析構(gòu)器的聲明,以在同一模塊中允許該符號(hào)用于內(nèi)聯(lián)代碼的聲明。聲明必須具有 internal
訪問(wèn)級(jí)別修飾符。被標(biāo)記為 usableFromInline
的結(jié)構(gòu)體或類它們屬性的類型只能是被標(biāo)記為 public 或者 usableFromInline
的類型。被標(biāo)記為 usableFromInline
的枚舉,它 case 的真實(shí)值或者關(guān)聯(lián)類型只能是被標(biāo)記為 public 或者 usableFromInline
的類型。
與 public
訪問(wèn)修飾符相同的是,該特性將聲明公開(kāi)為模塊公共接口的一部分。區(qū)別于 public
,編譯器不允許在模塊外部的代碼通過(guò)名稱引用 usableFromInline
標(biāo)記的聲明,即使導(dǎo)出了聲明符號(hào)也無(wú)法引用。但是,模塊外的代碼仍然可以通過(guò)運(yùn)行時(shí)與聲明符號(hào)進(jìn)行交互。
標(biāo)記為 inlinable
特性的聲明,在內(nèi)聯(lián)代碼中可以隱式使用。雖然 inlinable
或 usableFromInline
可以用于 internal
聲明,但這兩者不能同時(shí)使用。
warn-unqualified-access
該特性應(yīng)用于頂級(jí)函數(shù)、實(shí)例方法、類方法或靜態(tài)方法,以在沒(méi)有前置限定符(例如模塊名稱、類型名稱、實(shí)例變量或常量)的情況下使用該函數(shù)或方法時(shí)觸發(fā)警告。使用該特性可以減少在同一作用域里訪問(wèn)的同名函數(shù)之間的歧義。
例如,Swift 標(biāo)準(zhǔn)庫(kù)包含 min(_:_:)
頂級(jí)函數(shù)和用于序列比較元素的 min()
方法。序列方法聲明使用了 warn_unqualified_access
,以減少在 Sequence
擴(kuò)展中使用它們的歧義。
Interface Builder 特性是 Interface Builder 用來(lái)與 Xcode 同步的聲明特性。Swift 提供了以下的 Interface Builder 特性:IBAction
,IBSegueAction
,IBOutlet
,IBDesignable
,以及 IBInspectable
。這些特性與 Objective-C 中對(duì)應(yīng)的特性在概念上是相同的。
IBOutlet
和 IBInspectable
用于修飾一個(gè)類的屬性聲明。IBAction
和 IBSegueAction
特性用于修飾一個(gè)類的方法聲明,IBDesignable
用于修飾類的聲明。
應(yīng)用 IBAction
、IBSegueAction
、IBOutlet
、IBDesignable
或者 IBInspectable
特性都意味著同時(shí)應(yīng)用 objc
特性。
類型特性只能用于修飾類型。
autoclosure
這個(gè)特性通過(guò)把表達(dá)式自動(dòng)封裝成無(wú)參數(shù)的閉包來(lái)延遲表達(dá)式的計(jì)算。它可以修飾類型為返回表達(dá)式結(jié)果類型的無(wú)參數(shù)函數(shù)類型的函數(shù)參數(shù)。關(guān)于如何使用 autoclosure
特性的例子,請(qǐng)參閱 自動(dòng)閉包 和 函數(shù)類型。
convention
該特性用于修飾函數(shù)類型,它指出了函數(shù)調(diào)用的約定。
convention
特性總是與下面的參數(shù)之一一起出現(xiàn)。
swift
參數(shù)用于表示一個(gè) Swift 函數(shù)引用。這是 Swift 中函數(shù)值的標(biāo)準(zhǔn)調(diào)用約定。
block
參數(shù)用于表示一個(gè) Objective-C 兼容的塊引用。函數(shù)值會(huì)作為一個(gè)塊對(duì)象的引用,塊是一種 id
兼容的 Objective-C 對(duì)象,其中嵌入了調(diào)用函數(shù)。調(diào)用函數(shù)使用 C 的調(diào)用約定。
c
參數(shù)用于表示一個(gè) C 函數(shù)引用。函數(shù)值沒(méi)有上下文,不具備捕獲功能,并且使用 C 的調(diào)用約定。
除了少數(shù)例外,當(dāng)函數(shù)需要任何其他調(diào)用約定時(shí),可以轉(zhuǎn)換成任意調(diào)用約定的函數(shù)。非范型全局函數(shù)、不捕獲任何局部變量的局部函數(shù)或不捕獲任何局部變量的閉包可以轉(zhuǎn)換為 C 調(diào)用約定。其余的 Swift 函數(shù)不能轉(zhuǎn)換成 C 調(diào)用約定。一個(gè) Objective-C 塊調(diào)用約定的函數(shù)不能轉(zhuǎn)換成 C 調(diào)用約定。
escaping
在函數(shù)或者方法聲明上使用該特性,它表示參數(shù)將不會(huì)被存儲(chǔ)以供延遲執(zhí)行。這將確保參數(shù)不會(huì)超出函數(shù)調(diào)用的生命周期。在使用 escaping
特性聲明的函數(shù)類型中訪問(wèn)屬性和方法時(shí)需要顯式地使用 self.
。關(guān)于如何使用 escaping
特性的例子,請(qǐng)參閱 逃逸閉包。
你只能在 switch cases 語(yǔ)句中使用 switch case 特性。
unknown
該特性用于 switch case,用于沒(méi)有匹配上代碼編譯時(shí)已知 case 的情況。有關(guān)如何使用 unknown
特性的示例,可參閱 對(duì)未來(lái)枚舉的 case
進(jìn)行 switch
。
特性語(yǔ)法
attribute
特性 → @ 特性名 特性參數(shù)子句可選
attribute-name
特性名 → 標(biāo)識(shí)符
atribute-argument-clause
特性參數(shù)子句 → ( 均衡令牌列表可選 )
attributes
balanced-tokens
balanced-token
均衡令牌 → ( 均衡令牌列表可選 )
均衡令牌 → [ 均衡令牌列表可選 ]
均衡令牌 → { 均衡令牌列表可選 }
均衡令牌 → 任意標(biāo)識(shí)符,關(guān)鍵字,字面量或運(yùn)算符
均衡令牌 → 任意標(biāo)點(diǎn)除了 (,),[,],{,或 }