deinit: 當(dāng)一個(gè)類的實(shí)例即將被銷毀時(shí),會(huì)調(diào)用這個(gè)方法草姻。
class Person
{
var name:String
var age:Int
var gender:String
deinit
{
//從堆中釋放钓猬,并釋放的資源
}
}
extension:允許給已有的類、結(jié)構(gòu)體碴倾、枚舉逗噩、協(xié)議類型,添加新功能跌榔。
class Person
{
var name:String = ""
var age:Int = 0
var gender:String = ""
}
extension Person
{
func printInfo()
{
print("My name is \(name), I'm \(age) years old and I'm a \(gender).")
}
}
fileprivate:訪問控制權(quán)限异雁,只允許在定義源文件中訪問。
class Person
{
fileprivate var jobTitle:String = ""
}
extension Person
{
//當(dāng) extension 和 class 在同一個(gè)文件中時(shí)僧须,允許訪問
func printJobTitle()
{
print("My job is (jobTitle)")
}
}
inout:將一個(gè)值傳入函數(shù)纲刀,并可以被函數(shù)修改,然后將值傳回到調(diào)用處担平,來替換初始值示绊。適用于引用類型和值類型。 其實(shí)就是聲明參數(shù)為指針
func dangerousOp(_ error:inout NSError?)
{
error = NSError(domain: "", code: 0, userInfo: ["":""])
}
var potentialError:NSError?
dangerousOp(&potentialError)
//代碼運(yùn)行到這里暂论,potentialError 不再是 nil面褐,而是已經(jīng)被初始化
internal:訪問控制權(quán)限,允許同一個(gè)模塊下的所有源文件訪問取胎,如果在不同模塊下則不允許訪問展哭。
open:訪問控制權(quán)限,允許在定義的模塊外也可以訪問源文件里的所有類闻蛀,并進(jìn)行子類化匪傍。對(duì)于類成員,允許在定義的模塊之外訪問和重寫觉痛。
open var foo:String?
//這個(gè)屬性允許在 app 內(nèi)或 app 外重寫和訪問役衡。在開發(fā)框架的時(shí)候,會(huì)應(yīng)用到這個(gè)訪問修飾符薪棒。
private:訪問控制權(quán)限手蝎,只允許實(shí)體在定義的類以及相同源文件內(nèi)的 extension 中訪問榕莺。
class Person
{
private var jobTitle:String = ""
}
// 當(dāng) extension 和 class 不在同一個(gè)源文件時(shí)
extension Person
{
// 無法編譯通過,只有在同一個(gè)源文件下才可以訪問
func printJobTitle()
{
print("My job is (jobTitle)")
}
}
public:訪問控制權(quán)限柑船,允許在定義的模塊外也可以訪問源文件里的所有類帽撑,但只有在同一個(gè)模塊內(nèi)可以進(jìn)行子類化。對(duì)于類成員鞍时,允許在同個(gè)模塊下訪問和重寫。
public var foo:String? //只允許在 app 內(nèi)重寫和訪問扣蜻。
static:用于定義類方法逆巍,在類型本身進(jìn)行調(diào)用。此外還可以定義靜態(tài)成員莽使。
class Person
{
var jobTitle:String?
static func assignRandomName(_ aPerson:Person)
{
aPerson.jobTitle = "Some random job"
}
}
let somePerson = Person()
Person.assignRandomName(somePerson)
//somePerson.jobTitle 的值是 "Some random job"
struct:通用锐极、靈活的結(jié)構(gòu)體,是程序的基礎(chǔ)組成部分芳肌,并提供了默認(rèn)初始化方法灵再。與 class 不同,當(dāng) struct 在代碼中被傳遞時(shí)亿笤,是被拷貝的翎迁,并不使用引用計(jì)數(shù)。除此之外净薛,struct 沒有下面的這些功能:
- 使用繼承汪榔。
- 運(yùn)行時(shí)的類型轉(zhuǎn)換。
- 使用析構(gòu)方法肃拜。
struct Person
{
var name:String
var age:Int
var gender:String
}
typealias:給代碼中已經(jīng)存在的類痴腌,取別名。
typealias JSONDictionary = [String: AnyObject]
func parseJSON(_ deserializedData:JSONDictionary){}
defer:用于在程序離開當(dāng)前作用域之前燃领,執(zhí)行一段代碼士聪。
關(guān)閉文件
func foo() {
let fileDescriptor = open(url.path, O_EVTONLY)
defer {
close(fileDescriptor)
}
// use fileDescriptor...
}
加/解鎖:下面是 swift 里類似 Objective-C 的 synchronized block 的一種寫法,可以使用任何一個(gè) NSObject 作 lock
func foo() {
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}
// do something...
}
defer 的執(zhí)行時(shí)機(jī):
defer 的執(zhí)行時(shí)機(jī)緊接在離開作用域之后猛蔽,但是是在其他語句之前剥悟。這個(gè)特性為 defer 帶來了一些很“微妙”的使用方式。比如從 0 開始的自增:
class Foo {
var num = 0
func foo() -> Int {
defer { num += 1 }
return num
}
// 沒有 `defer` 的話我們可能要這么寫
// func foo() -> Int {
// num += 1
// return num - 1
// }
}
let f = Foo()
f.foo() // 0
f.foo() // 1
f.num // 2
fallthrough:顯式地允許從當(dāng)前 case 跳轉(zhuǎn)到下一個(gè)相鄰 case 繼續(xù)執(zhí)行代碼枢舶。
let box = 1
switch box
{
case 0:
print("Box equals 0")
fallthrough
case 1:
print("Box equals 0 or 1")
default:
print("Box doesn't equal 0 or 1")
}
guard:當(dāng)有一個(gè)以上的條件不滿足要求時(shí)懦胞,將離開當(dāng)前作用域。同時(shí)還提供解包可選類型的功能凉泄。
private func printRecordFromLastName(userLastName: String?)
{
guard let name = userLastName, name != "Null" else
{
//userLastName = "Null"躏尉,需要提前退出
return
}
//繼續(xù)執(zhí)行代碼
print(dataStore.findByLastName(name))
}
1.guard關(guān)鍵字必須使用在函數(shù)中。
2.guard關(guān)鍵字必須和else同時(shí)出現(xiàn)后众。
3.guard關(guān)鍵字只有條件為false的時(shí)候才能走else語句 相反執(zhí)行后邊語句胀糜。
repeat:在使用循環(huán)的判斷條件之前颅拦,先執(zhí)行一次循環(huán)中的代碼。
repeat
{
print("Always executes at least once before the condition is considered")
}
while 1 > 2
where:要求關(guān)聯(lián)類型必須遵守特定協(xié)議教藻,或者類型參數(shù)和關(guān)聯(lián)類型必須保持一致距帅。也可以用于在 case 中提供額外條件,用于滿足控制表達(dá)式括堤。
- 增加判斷條件
for i in 0…3 where i % 2 == 0
{
print(i) //打印 0 和 2
}
- 協(xié)議使用where碌秸, 只有基類實(shí)現(xiàn)了當(dāng)前協(xié)議才能添加擴(kuò)展。 換個(gè)說法悄窃, 多個(gè)類實(shí)現(xiàn)了同一個(gè)協(xié)議讥电,該語法根據(jù)類名分別為這些類添加擴(kuò)展, 注意是分別(以類名區(qū)分)T埂6鞯小!
protocol SomeProtocol {
func someMethod()
}
class A: SomeProtocol {
let a = 1
func someMethod() {
print("call someMethod")
}
}
class B {
let a = 2
}
//基類A繼承了SomeProtocol協(xié)議才能添加擴(kuò)展
extension SomeProtocol where Self: A {
func showParamA() {
print(self.a)
}
}
//反例横媚,不符合where條件
extension SomeProtocol where Self: B {
func showParamA() {
print(self.a)
}
}
let objA = A()
let objB = B() //類B沒實(shí)現(xiàn)SomeProtocol纠炮, 所有沒有協(xié)議方法
objA.showParamA() //輸出1
as:類型轉(zhuǎn)換運(yùn)算符,用于嘗試將值轉(zhuǎn)成其它類型灯蝴。
- as : 數(shù)值類型轉(zhuǎn)換
let age = 28 as Int
let money = 20 as CGFloat
let cost = (50 / 2) as Double
switch person1 {
case let person1 as Student:
print("是Student類型恢口,打印學(xué)生成績單...")
case let person1 as Teacher:
print("是Teacher類型,打印老師工資單...")
default: break
}
- as!:向下轉(zhuǎn)型(Downcasting)時(shí)使用绽乔。由于是強(qiáng)制類型轉(zhuǎn)換弧蝇,如果轉(zhuǎn)換失敗會(huì)報(bào) runtime 運(yùn)行錯(cuò)誤。
let person : Person = Teacher("Jimmy Lee")
let jimmy = person as! Teacher
- as?: as? 和 as! 操作符的轉(zhuǎn)換規(guī)則完全一樣折砸。但 as? 如果轉(zhuǎn)換不成功的時(shí)候便會(huì)返回一個(gè) nil 對(duì)象看疗。成功的話返回可選類型值。由于 as? 在轉(zhuǎn)換失敗的時(shí)候也不會(huì)出現(xiàn)錯(cuò)誤睦授,所以對(duì)于如果能確保100%會(huì)成功的轉(zhuǎn)換則可使用 as!两芳,否則使用 as?
let a = 13 as! String
print(a)
//會(huì)crash
let a = 13 as? String
print(a)
//輸出為nil
is:類型檢查運(yùn)算符,用于確定實(shí)例是否為某個(gè)子類類型去枷。
class Person {}
class Programmer : Person {}
class Nurse : Person {}
let people = [Programmer(), Nurse()]
for aPerson in people
{
if aPerson is Programmer
{
print("This person is a dev")
}
else if aPerson is Nurse
{
print("This person is a nurse")
}
}
nil:在 Swift 中表示任意類型的無狀態(tài)值怖辆。
Swift的nil和OC中的nil不一樣.在OC中,nil是一個(gè)指向不存在對(duì)象的指針.而在Swift中,nil不是指針,它是一個(gè)不確定的值.用來表示值缺失.任何類型的optional都可以被設(shè)置為nil.
而在OC中,基本數(shù)據(jù)類型和結(jié)構(gòu)體是不能被設(shè)置為nil的.
給optional的常量或者變量賦值為nil.來表示他們的值缺失情況.一個(gè)optional常量或者變量如果在初始化的時(shí)候沒有被賦值,他們自動(dòng)會(huì)設(shè)置成nil.
class Person{}
struct Place{}
//任何 Swift 類型或?qū)嵗梢詾?nil
var statelessPerson:Person? = nil
var statelessPlace:Place? = nil
var statelessInt:Int? = nil
var statelessString:String? = nil
super:在子類中,暴露父類的方法删顶、屬性竖螃、下標(biāo)。
class Person
{
func printName()
{
print("Printing a name. ")
}
}
class Programmer : Person
{
override func printName()
{
super.printName()
print("Hello World!")
}
}
let aDev = Programmer()
aDev.printName() //打印 Printing a name. Hello World!
self:任何類型的實(shí)例都擁有的隱式屬性逗余,等同于實(shí)例本身特咆。此外還可以用于區(qū)分函數(shù)參數(shù)和成員屬性名稱相同的情況。
class Person
{
func printSelf()
{
print("This is me: (self)")
}
}
let aPerson = Person()
aPerson.printSelf() //打印 "This is me: Person"
Self:在協(xié)議中,表示遵守當(dāng)前協(xié)議的實(shí)體類型洁奈。
protocol Printable
{
func printTypeTwice(otherMe:Self)
}
struct Foo : Printable
{
func printTypeTwice(otherMe: Foo)
{
print("I am me plus (otherMe)")
}
}
let aFoo = Foo()
let anotherFoo = Foo()
aFoo.printTypeTwice(otherMe: anotherFoo) //打印 I am me plus Foo()
_:用于匹配或省略任意值的通配符。
for _ in 0..<3
{
print("Just loop 3 times, index has no meaning")
}
另外一種用法:
let _ = Singleton() //忽略不使用的變量
以#開頭的關(guān)鍵字
#available:基于平臺(tái)參數(shù)夺谁,通過 if菜职,while青抛,guard 語句的條件,在運(yùn)行時(shí)檢查 API 的可用性酬核。
if #available(iOS 10, *)
{
print("iOS 10 APIs are available")
}
#colorLiteral:在 playground 中使用的字面表達(dá)式蜜另,用于創(chuàng)建顏色選取器,選取后賦值給變量愁茁。
let aColor = #colorLiteral //創(chuàng)建顏色選取器
#column:一種特殊的字面量表達(dá)式蚕钦,用于獲取字面量表示式的起始列數(shù)。
class Person
{
func printInfo()
{
print("Some person info - on column (#column)")
}
}
let aPerson = Person()
aPerson.printInfo() //Some person info - on column 53
#function:特殊字面量表達(dá)式鹅很,返回函數(shù)名稱。在方法中罪帖,返回方法名促煮。在屬性的 getter 或者 setter 中,返回屬性名整袁。在特殊的成員中菠齿,比如 init 或 subscript 中,返回關(guān)鍵字名稱坐昙。在文件的最頂層時(shí)绳匀,返回當(dāng)前所在模塊名稱。
class Person
{
func printInfo()
{
print("Some person info - inside function (#function)")
}
}
let aPerson = Person()
aPerson.printInfo() //Some person info - inside function printInfo()
#line:特殊字面量表達(dá)式炸客,用于獲取當(dāng)前代碼的行數(shù)疾棵。
class Person
{
func printInfo()
{
print("Some person info - on line number (#line)")
}
}
let aPerson = Person()
aPerson.printInfo() //Some person info - on line number 5
#selector:用于創(chuàng)建 Objective-C selector 的表達(dá)式,可以靜態(tài)檢查方法是否存在痹仙,并暴露給 Objective-C是尔。
//靜態(tài)檢查,確保 doAnObjCMethod 方法存在
control.sendAction(#selector(doAnObjCMethod), to: target, forEvent: event)
convenience:
在 Swift 中开仰,為保證安全性拟枚,init 方法只能調(diào)用一次,且在 init 完成后众弓,保證所有非 Optional 的屬性都已經(jīng)被初始化恩溅。
每個(gè)類都有指定的初始化方法:designated initializer,這些初始化方法是子類必須調(diào)用的谓娃,為的就是保證父類的屬性都初始化完成了脚乡。
而如果不想實(shí)現(xiàn)父類的 designated initializer,可以添加 convenience 關(guān)鍵字傻粘,自己實(shí)現(xiàn)初始化邏輯每窖。
convenience 初始化不能調(diào)用父類的初始化方法帮掉,只能調(diào)用同一個(gè)類中的 designated initializer。
由于 convenience 初始化不安全窒典,所以 Swift 不允許 convenience initializer 被子類重寫蟆炊,限制其作用范圍。
class People {
var name: String
init(name: String) {
self.name = name
}
}
通過extension給原有的People類增加init方法:
// 使用convenience增加init方法
extension People {
convenience init(smallName: String) {
self.init(name: smallName)
}
}
結(jié)下來瀑志,Student類繼承父類People
class Student: People {
var grade: Int
init(name: String, grade: Int) {
self.grade = grade
super.init(name: name)
// 無法調(diào)用
// super.init(smallName: name)
}
// 可以被重寫
override init(name: String) {
grade = 1
super.init(name: name)
}
// 無法重寫涩搓,編譯不通過
override init(smallName: String) {
grade = 1
super.init(smallName: smallName)
}
}
子類對(duì)象調(diào)用父類的convenience的init方法:只要在子類中實(shí)現(xiàn)重寫了父類convenience方法所需要的init方法的話,我們在子類中就可以使用父類的convenience初始化方法了
class People {
var name: String
init(name: String) {
self.name = name
}
}
// 使用convenience增加init方法
extension People {
convenience init(smallName: String) {
self.init(name: smallName)
}
}
// 子類
class Teacher: People {
var course: String
init(name: String, course: String) {
self.course = course
super.init(name: name)
}
override init(name: String) {
self.course = "math"
super.init(name: name)
}
}
// 調(diào)用convenience的init方法
let xiaoming = Teacher(smallName: "xiaoming")
- 總結(jié):子類的designated初始化方法必須調(diào)用父類的designated方法劈猪,以保證父類也完成初始化昧甘。
required關(guān)鍵字
對(duì)于某些我們希望子類中一定實(shí)現(xiàn)的designated初始化方法,我們可以通過添加required關(guān)鍵字進(jìn)行限制战得,強(qiáng)制子類對(duì)這個(gè)方法重寫充边。
required修飾符的使用規(guī)則:
- required修飾符只能用于修飾類初始化方法。
- 當(dāng)子類含有異于父類的初始化方法時(shí)(初始化方法參數(shù)類型和數(shù)量異于父類)常侦,子類必須要實(shí)現(xiàn)父類的required初始化方法浇冰,并且也要使用required修飾符而不是override。
- 當(dāng)子類沒有初始化方法時(shí)聋亡,可以不用實(shí)現(xiàn)父類的required初始化方法肘习。
代碼:
class MyClass {
var str:String
required init(str:String) {
self.str = str
}
}
class MySubClass:MyClass
{
init(i:Int) {
super.init(str:String(i))
}
}
// 編譯錯(cuò)誤
MySubClass(i: 123)
會(huì)報(bào)錯(cuò),因?yàn)槟銢]有實(shí)現(xiàn)父類中必須實(shí)現(xiàn)的方法坡倔。正確的寫法:
class MyClass{
var str: String?
required init(str: String?) {
self.str = str
}
}
class MySubClass: MyClass{
init(i: Int) {
super.init(str: String(i))
}
required init(str: String?) {
fatalError("init(str:) has not been implemented")
}
}
從上面的代碼中漂佩,不難看出子類需要添加異于父類的初始化方法,必須要重寫有required的修飾符的初始化方法罪塔,并且也要使用required修飾符而不是override投蝉,請千萬注意!
如果子類中并沒有不同于父類的初始化方法垢袱,Swift會(huì)默認(rèn)使用父類的初始化方法:
class MyClass{
var str: String?
required init(str: String?) {
self.str = str
}
}
class MySubClass: MyClass{
}
var MySubClass(str: "hello swift")
在這種情況下墓拜,編譯器不會(huì)報(bào)錯(cuò),因?yàn)槿绻宇悰]有任何初始化方法時(shí)请契,Swift會(huì)默認(rèn)使用父類的初始化方法咳榜。
dynamic && @objc
1.@objc
OC 是基于運(yùn)行時(shí),遵循了 KVC 和動(dòng)態(tài)派發(fā)爽锥,而 Swift 為了追求性能涌韩,在編譯時(shí)就已經(jīng)確定,而不需要在運(yùn)行時(shí)的氯夷,在 Swift 類型文件中臣樱,為了解決這個(gè)問題,需要暴露給 OC 使用的任何地方(類,屬性雇毫,方法等)的生命前面加上 @objc 修飾符
如果用 Swift 寫的 class 是繼承 NSObject 的話玄捕, Swift 會(huì)默認(rèn)自動(dòng)為所有非 private 的類和成員加上@objc
在Swift中,我們在給button添加點(diǎn)擊事件時(shí)棚放,對(duì)應(yīng)的點(diǎn)擊事件的觸發(fā)方法就需要用@objc來修飾
2. dynamic
Swift 中的函數(shù)可以是靜態(tài)調(diào)用枚粘,靜態(tài)調(diào)用會(huì)更快。當(dāng)函數(shù)是靜態(tài)調(diào)用的時(shí)候飘蚯,就不能從字符串查找到對(duì)應(yīng)的方法地址了馍迄。這樣 Swift 跟 Objective-C 交互時(shí),Objective-C 動(dòng)態(tài)查找方法地址局骤,就有可能找不到 Swift 中定義的方法攀圈。
這樣就需要在 Swift 中添加一個(gè)提示關(guān)鍵字,告訴編譯器這個(gè)方法是可能被動(dòng)態(tài)調(diào)用的峦甩,需要將其添加到查找表中赘来。這個(gè)就是關(guān)鍵字 dynamic 的作用。
willSet與didSet
- willSet在設(shè)置新的值之前調(diào)用凯傲。willSet可以帶一個(gè)newName的參數(shù)撕捍,沒有的話,該參數(shù)默認(rèn)命名為newValue
- didSet在新的值被設(shè)置之后立即調(diào)用泣洞。didSet可以帶一個(gè)oldName的參數(shù),表示舊的屬性默色,不帶的話默認(rèn)命名為oldValue
- willSet和didSet觀察器在屬性初始化過程中不會(huì)被調(diào)用球凰。只有在初始化上下文之外,當(dāng)設(shè)置屬性值時(shí)才會(huì)調(diào)用腿宰。
- 即使是設(shè)置的值和原來值相同呕诉,willSet和didSet也會(huì)被調(diào)用
var counter: Int = 0{
willSet(newTotal){
print("計(jì)數(shù)器: \(newTotal)")
}
didSet{
if counter > oldValue {
print("新增數(shù) \(counter - oldValue)")
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
//結(jié)果:
//計(jì)數(shù)器: 100
//新增數(shù) 100
//計(jì)數(shù)器: 800
//新增數(shù) 700
final
- final修飾符只能修飾類,表明該類不能被其他類繼承吃度,也就是它沒資格當(dāng)父類甩挫。
- final修飾符也可以修飾類中的屬性、方法和下標(biāo)椿每,但前提是該類并沒有被final修飾過伊者。
- final不能修飾結(jié)構(gòu)體和枚舉。
final正確的使用場景 - 權(quán)限控制
也就是說這個(gè)類或方法不希望被繼承和重寫间护,具體情況如下:
類或者方法的功能確實(shí)已經(jīng)完備了
這種通常是一些輔助性質(zhì)的工具類或者方法亦渗,特別那種只包含類方法而沒有實(shí)例方法的類。比如MD5加密類這種汁尺,算法都十分固定法精,我們基本不會(huì)再繼承和重寫。避免子類繼承和修改造成危險(xiǎn)
有些方法如果被子類繼承重寫會(huì)造成破壞性的后果,導(dǎo)致無法正常工作搂蜓,則需要將其標(biāo)為final加以保護(hù)狼荞。為了讓父類中某些代碼一定會(huì)執(zhí)行
父類的方法如果想要其中一些關(guān)鍵代碼在繼承重寫后仍必須執(zhí)行(比如狀態(tài)配置、認(rèn)證等)帮碰。我們可以把父類的方法定義成final相味,同時(shí)將內(nèi)部可以繼承的部分剝離出來,供子類繼承重寫收毫。下面通過一段代碼演示:
class Parent {
final func method1() {
//權(quán)限驗(yàn)證(必須執(zhí)行)
//.....
method2()
//下面是日志記錄(必須執(zhí)行)
//..........
}
func method2(){
//父類的實(shí)現(xiàn)
//......
}
}
class Child : Parent {
//只能重寫父類的method2方法攻走,不能重寫method1方法
override func method2() {
//子類的實(shí)現(xiàn)
//......
}
}
indirect
指明在枚舉類型中,存在成員使用相同枚舉類型的實(shí)例作為關(guān)聯(lián)值的情況此再。
indirect enum Entertainment
{
case eventType(String)
case oneEvent(Entertainment)
case twoEvents(Entertainment, Entertainment)
}
let dinner = Entertainment.eventType("Dinner")
let movie = Entertainment.eventType("Movie")
let dateNight = Entertainment.twoEvents(dinner, movie)
lazy
指明屬性的初始值昔搂,直到第一次被使用時(shí),才進(jìn)行初始化输拇。
class Person
{
lazy var personalityTraits = {
//昂貴的數(shù)據(jù)庫開銷
return ["Nice", "Funny"]
}()
}
let aPerson = Person()
aPerson.personalityTraits //當(dāng) personalityTraits 首次被訪問時(shí)摘符,數(shù)據(jù)庫才開始工作
mutating
在Swift中,包含三種類型(type): structure,enumeration,class
其中structure和enumeration是值類型(value type),class是引用類型(reference type)
Swift中protocol的功能比OC中強(qiáng)大很多策吠,不僅能再class中實(shí)現(xiàn)逛裤,同時(shí)也適用于struct、enum猴抹。但是struct带族、enum都是值類型,每個(gè)值都是有默認(rèn)的蟀给,所以在實(shí)例方法中不能改變蝙砌,因此就要用mutating關(guān)鍵字,這個(gè)關(guān)鍵字可以讓在此方法中值的改變跋理,會(huì)返回到原始結(jié)構(gòu)里邊
protocol Vehicle {
var numberOfWheels: Int {get}
var color: UIColor {get set}
mutating func changeColor()
}
struct MyCar: Vehicle {
let numberOfWheels = 4
var color = UIColor.blue
mutating func changeColor() {
color = .red
}
}
subscript
- 下標(biāo)(subscript)在數(shù)組和字典中使用择克,但是你可以給任何類型(枚舉,結(jié)構(gòu)體前普,類)增加 下標(biāo)subscript 的功能肚邢;
- subscript的語法類似實(shí)例方法、計(jì)算屬性拭卿,其本質(zhì)就是方法骡湖;
struct Person {
var age = 0
var no = 0
subscript(index: Int) -> Int {
set {
if index == 0 {
age = newValue
} else {
no = newValue
}
}
get {
if index == 0 {
return age
} else {
return no
}
}
}
}
var p = Person()
p[0] = 10
p[1] = 20
print(p.age) // 10
print(p[0]) // 10
print(p.no) // 20
print(p[1]) // 20
- subscript 的返回值類型決定了:
1.get 方法的返回值類型;
2.set 方法中 newValue 的類型记劈; - subscript 可以接受多個(gè)參數(shù)勺鸦,并且是任意類型;
- subscript 可以沒有 set 方法目木,但必須要有 get 方法换途;
- 如果只有 get 方法懊渡,可以省略;
struct Person {
var age = 30
subscript(index: Int) -> Int {
if index == 0 {
return age
} else {
return age * 2
}
}
}
var p = Person()
print(p[0]) // 30
print(p[1]) // 60
nonmutating
nonmutating關(guān)鍵字军拟,一般配合set使用剃执。如
protocol Settings {
subscript(key: String) -> AnyObject? { get nonmutating set }
}
它告訴編譯器不會(huì)修改實(shí)例內(nèi)部的值,也就是set時(shí)懈息,不會(huì)改變?nèi)魏纹渌淖兞俊?/p>
struct Test2 {
var b: Int {
get {
return 2
}
nonmutating set {
print("\(newValue)")
}
}
}
let t = Test2()
t.b = 3
print(t.b)
optional
用于指明協(xié)議中的可選方法肾档。遵守該協(xié)議的實(shí)體類可以不實(shí)現(xiàn)這個(gè)方法。
@objc protocol Foo
{
func requiredFunction()
@objc optional func optionalFunction()
}
class Person : Foo
{
func requiredFunction()
{
print("Conformance is now valid")
}
}
override
指明子類會(huì)提供自定義實(shí)現(xiàn)辫继,覆蓋父類的實(shí)例方法怒见、類型方法、實(shí)例屬性姑宽、類型屬性遣耍、下標(biāo)。如果沒有實(shí)現(xiàn)炮车,則會(huì)直接繼承自父類舵变。
class Person
{
func printInfo()
{
print("I'm just a person!")
}
}
class Programmer : Person
{
override func printInfo()
{
print("I'm a person who is a dev!")
}
}
let aPerson = Person()
let aDev = Programmer()
aPerson.printInfo() //打印 I'm just a person!
aDev.printInfo() //打印 I'm a person who is a dev!
unowned && weak
- weak:弱引用對(duì)象的引用計(jì)數(shù)不會(huì)+1, 必須為可選類型變量
在聲明弱引用對(duì)象是必須用var關(guān)鍵字, 不能用let.
因?yàn)槿跻米兞吭跊]有被強(qiáng)引用的條件下會(huì)變?yōu)閚il, 而let常量在運(yùn)行的時(shí)候不能被改變.
class XDTest {
//會(huì)報(bào)錯(cuò)
weak let tentacle = Tentacle() //let is a constant! All weak variables MUST be mutable.
}
- unowned:相當(dāng)于__unsafe_unretained, 不安全. 必須為非可選類型.
unowned引用是non-zeroing(非零的), 在ARC銷毀內(nèi)存后,不會(huì)被賦為nil, 這表示著當(dāng)一個(gè)對(duì)象被銷毀時(shí), 它指引的對(duì)象不會(huì)清零. 也就是說使用unowned引用在某些情況下可能導(dǎo)致dangling pointers(野指針). 所以在訪問無主引用的時(shí)候瘦穆,要確保其引用正確纪隙,不然會(huì)引起內(nèi)存崩潰.
throw && rethrow
throws的使用很簡單,只需要在可能出現(xiàn)異常的函數(shù)或者方法后面添加throws扛或。
經(jīng)過這個(gè)關(guān)鍵字修飾的函數(shù)绵咱,在調(diào)用的時(shí)候,需要程序員加上do-catch來調(diào)用.rethrows是異常往上傳遞的關(guān)鍵字熙兔。上面說了throws用在可能出現(xiàn)異常的函數(shù)或者方法中麸拄,而rethrows針對(duì)的不是函數(shù)或者方法的本身,而是它攜帶的閉包類型的參數(shù)黔姜,當(dāng)它的閉包類型的參數(shù)throws的時(shí)候,我們要使用rethrows繼續(xù)將這個(gè)異常往上傳遞蒂萎, 直到被調(diào)用者使用到秆吵。這相比throws多一個(gè)傳遞的環(huán)節(jié)。
@dynamicMemberLookup
這個(gè)特性中文可以叫動(dòng)態(tài)查找成員五慈。在使用@dynamicMemberLookup標(biāo)記了對(duì)象后(對(duì)象纳寂、結(jié)構(gòu)體、枚舉泻拦、protocol)毙芜,實(shí)現(xiàn)了subscript(dynamicMember member: String)方法后我們就可以訪問到對(duì)象不存在的屬性。如果訪問到的屬性不存在争拐,就會(huì)調(diào)用到實(shí)現(xiàn)的 subscript(dynamicMember member: String)方法腋粥,key 作為 member 傳入這個(gè)方法。
@dynamicMemberLookup
struct Person {
subscript(dynamicMember member: String) -> String {
let properties = ["nickname": "Zhuo", "city": "Hangzhou"]
return properties[member, default: "undefined"]
}
}
//執(zhí)行以下代碼
let p = Person()
print(p.city)
print(p.nickname)
print(p.name)