Swift語言中的面向?qū)ο筇匦?/h1>

面向?qū)ο笃?/h1>

Swift語言中的面向?qū)ο筇匦?/h2>

在現(xiàn)代計算機(jī)語言中已卸,面向?qū)ο笫欠浅V匾奶匦裕琒wift語言也提供了面向?qū)ο蟮闹С帧6以赟wift語言中峰伙,不僅類具有面向?qū)ο筇匦裕Y(jié)構(gòu)體和枚舉也都具有面向?qū)ο筇匦浴?/p>

面向?qū)ο蟾拍詈突咎卣?/h3>

面向?qū)ο?OOP)是現(xiàn)代流行的程序設(shè)計方法该默,是一種主流的程序設(shè)計規(guī)范瞳氓。其基本思想是使用對象、類栓袖、繼承匣摘、封裝、屬性裹刮、方法等基本概念來進(jìn)行程序設(shè)計音榜。從現(xiàn)實世界中客觀存在的事物出發(fā)來構(gòu)造軟件系統(tǒng),并且在系統(tǒng)構(gòu)造中盡可能運用人類的自然思維方式必指。

**OOP的基本特征包括:封裝性囊咏、繼承性和多態(tài)性。

  • 封裝性 封裝性就是盡可能隱蔽對象的內(nèi)部細(xì)節(jié),對外形成一個邊界梅割,只保留有限的對外接口使之與外部發(fā)生聯(lián)系霜第。

  • 繼承性 一些特殊類能夠具有一般類的全部屬性和方法,這稱做特殊類對一般類的繼承户辞。通常我們稱一般類為父類(或基類)泌类,特殊類為子類(或派生類)。

  • 多態(tài)性 對象的多態(tài)性是指在父類中定義的屬性或方法被子類繼承之后底燎,可以使同一個屬性或方法在父類及其各個子類中具有不同的含義刃榨,這稱為多態(tài)性。例如動物都有吃飯的方法双仍,但是老鼠的吃飯方法和貓的吃飯方法是截然不同的枢希。


Swift中的面向?qū)ο箢愋?/h3>

面向?qū)ο螅诓煌挠嬎銠C(jī)語言中朱沃,其具體的體現(xiàn)也是不同的苞轿。在C++和Java等語言中通過類實現(xiàn)面向?qū)ο螅赟wift語言中通過類和結(jié)構(gòu)體(struct)實現(xiàn)面向?qū)ο蠖何铮赟wift語言中搬卒,枚舉(enum)也具有面向?qū)ο筇匦浴=Y(jié)構(gòu)體和枚舉在其他語言中完全沒有面向?qū)ο筇匦贼嶙浚琒wift語言賦予了它們面向?qū)ο笊?/p>

提示:由于OOP中的類在Swift語言中涵蓋了枚舉契邀、類和結(jié)構(gòu)體。為了防止與OOP中的類發(fā)生沖突失暴,在此把Swift中的這3種類型稱為“Swift面向?qū)ο箢愋汀薄?/p>

在面向?qū)ο笾信髅牛瑢㈩悇?chuàng)建對象的過程稱為實例化,因此將對象稱為實例锐帜,但是在Swift中田盈,結(jié)構(gòu)體和枚舉的實例不稱為“對象”,因為結(jié)構(gòu)體和枚舉并不是徹底的面向?qū)ο箢愋徒裳郑前艘恍┟嫦驅(qū)ο蟮奶攸c。例如简软,在Swift中繼承只發(fā)生在類上蛮拔,結(jié)構(gòu)體和枚舉不能繼承。

在Swift中痹升,面向?qū)ο蟮母拍钸€有:屬性建炫、方法、擴(kuò)展和協(xié)議等疼蛾,這些概念對于枚舉肛跌、類和結(jié)構(gòu)體等不同類型有可能不同。

枚舉

在C和Objective-C中,枚舉用于管理一組相關(guān)常量集合衍慎,通過使用枚舉可以提高程序的可讀性转唉,使代碼更清晰,更易于維護(hù)稳捆。而在Swift中赠法,枚舉的作用已經(jīng)不僅僅是定義一組常量、提高程序的可讀性了乔夯,它還具有了面向?qū)ο筇匦浴?/p>

枚舉的語法格式:

enum 枚舉名

{

枚舉的定義

}

"枚舉名"是該枚舉類型的名稱砖织。它首先應(yīng)該是有效的標(biāo)識符,其次應(yīng)該是遵守面向?qū)ο蟮拿?guī)范末荐。它應(yīng)該是一個名稱侧纯,如果采用英文單詞命名,首字母應(yīng)該大寫甲脏,盡量用一個英文單詞茂蚓。這個命名規(guī)范也適用于類和結(jié)構(gòu)體的命名√昊希“枚舉的定義”是枚舉的核心聋涨,它由一組成員值和一組相關(guān)值組成。

成員值

在枚舉類型中定義一組成員负乡,與C和Objective-C中枚舉的主要作用是一樣的牍白,不同的是,在C和Objective-C中成員值是整數(shù)類型抖棘,因此在C和Objective-C中枚舉類型就是整數(shù)類型茂腥。

而在Swift中,枚舉的成員值默認(rèn)情況下不是整數(shù)類型切省。

聲明枚舉示例:

print("--枚舉示例---")

enum WeekDays {
    case Monday
    case Tuesday
    case Wednesday
    case Thursday
    case Friday
}

上述代碼聲明了WeekDays枚舉最岗,表示一周中的每個工作日膀藐,其中定義了5個成員值:Monday包雀、Tuesday、Wdenesday具钥、Thursday芙盘、Friday驯用,這些成員值并不是整數(shù)類型。

在這些成員值前面還要加上case關(guān)鍵字儒老,也可以將多個成員值放在同一行蝴乔,用逗號隔開,如下:

enum WeekDays_ {
    case Monday, Tuesday, Wednesday, Thursday, Friday
}

看一個示例驮樊,代碼如下:

print("---使用枚舉示例----")

var day = WeekDays.Friday
day = WeekDays.Wednesday
day = .Monday

func writeGreeting(day : WeekDays) {
    switch day {
    case .Monday:
        print("星期一好!")
    case .Tuesday:
        print("星期二好!")
    case .Wednesday:
        print("星期三好!")
    case .Thursday:
        print("星期四好!")
    case .Friday:
        print("星期五好!")
    }
}

writeGreeting(day)
writeGreeting(WeekDays.Friday)

前三行代碼均是給變量day賦值薇正,可以采用完整的“枚舉類型名.成員值”的形式片酝,也可以省略枚舉類型,采用“.成員值”的形式挖腰。這種省略形式能夠訪問的前提是雕沿,Swift能夠根據(jù)上下文環(huán)境推斷類型。

枚舉類型與switch語句能夠很好地配合使用曙聂,在switch語句中使用枚舉類型可以沒有default分支晦炊,這在使用其他類型時是不允許的。

需要注意宁脊,在switch中使用枚舉類型時断国,switch語句中的case必須全面包含枚舉中的所有成員,不能多也不能少榆苞,包括使用default的情況下稳衬,default也表示某個枚舉成員。

使用default分支的代碼:

print("---使用default分支---")

func writeGreeting_(day :WeekDays) {
    
    switch day {
    case .Monday:
        print("星期一好!")
    case .Tuesday:
        print("星期二好!")
    case .Wednesday:
        print("星期三好!")
    case .Thursday:
        print("星期四好!")
    default:
        print("星期五好!")
    }
}

在上面示例中坐漏,default表示的是Friday枚舉成員薄疚,在這種情況下,F(xiàn)riday枚舉成員的case分支不能再出現(xiàn)了赊琳。

原始值

為每個成員提供某種具體類型的默認(rèn)值街夭,可以為枚舉類型提供原始值(raw values)聲明,這些原始值類型可以是:字符躏筏、字符串板丽、整數(shù)和浮點數(shù)等。

原始值枚舉的語法格式如下:

enum 枚舉名 : 數(shù)據(jù)類型

{

case 成員名 = 默認(rèn)值

...

}

在“枚舉名”后面跟“:”和“數(shù)據(jù)類型”就可以聲明原始值枚舉的類型趁尼,然后在定義case成員的時候需要提供默認(rèn)值埃碱。

以下代碼是聲明枚舉示例:

print("---原始值---")

enum WeekDays__ : Int {
    case Monday             = 0
    case Tuesday            = 1
    case Wednesday          = 2
    case Thursday           = 3
    case Friday             = 4
}

聲明的WeekDays枚舉類型的原始值類型是Int,需要給每個成員賦值酥泞,只要是Int類型都可以砚殿,但是每個分支不能重復(fù)。還可以采用如下簡便寫法芝囤,只需要給第一個成員賦值即可似炎,后面的成員值會依次加1。

print("--原始值--簡便寫法--")

enum WeekDays___ : Int {
    case Monday = 0, Tuesday, Wednesday, Thursday, Friday
}

完整示例代碼:

print("---完整示例代碼----")

print("---原始值---")

enum WeekDays : Int {
    case Monday             = 0
    case Tuesday            = 1
    case Wednesday          = 2
    case Thursday           = 3
    case Friday             = 4
}

var day = WeekDays.Friday
day = WeekDays.Wednesday

func writeGreeting(day : WeekDays) {
    switch day {
    case .Monday:
        print("星期一好!")
    case .Tuesday:
        print("星期二好!")
    case .Wednesday:
        print("星期三好!")
    case .Thursday:
        print("星期四好!")
    case .Friday:
        print("星期五好!")
    }
}

let friday = WeekDays.Friday.rawValue

let thursday = WeekDays(rawValue: 3)

if (WeekDays.Friday.rawValue == 4) {
    print("今天是星期五")
}

writeGreeting(day)
writeGreeting(WeekDays.Friday)

let friday = WeekDays.Friday.rawValue該句代碼是通過WeekDays.Friday的方法rawValue轉(zhuǎn)換為原始值凡人。雖然在定義的時候Friday被賦值為4名党,但是并不等于WeekDays.Friday就是整數(shù)4了,而是它的原始值為整數(shù)4挠轴,因此下面的比較是錯誤的。

if (WeekDays.Friday == 4) {
    print("今天是星期五")
}

.rawValue方法是將成員值轉(zhuǎn)換為原始值耳幢,相反岸晦,WeekDays(rewValue : 3)方法是將原始值轉(zhuǎn)換為成員值欧啤。

相關(guān)值

在Swift中除了定義一組成員值,還可以定義一組相關(guān)值(associated values)启上,它有點類似于C中的聯(lián)合類型邢隧。

枚舉類型的聲明:

print("--相關(guān)值---")

enum Figure {
    case Rectangle(Int, Int)
    case Circle(Int)
}

枚舉類型Figure(圖形)有兩個相關(guān)值:Rectangle(矩形)和Circle(圓形)。Rectangle和Circle是與Figure有關(guān)聯(lián)的相關(guān)值冈在,它們都是元組類型倒慧,對于一個特定的Figure實例,只能是其中一個相關(guān)值包券。

示例纫谅,代碼如下:

func printFigure(figure :   Figure) {
    
    switch figure {
    case .Rectangle(let width, let height):
        print("矩形的寬:\(width) 高:\(height)")
    case .Circle(let radius) :
        print("圓形的半徑:\(radius)")
    }
}

var figure = Figure.Rectangle(1024, 768)
printFigure(figure)

figure = .Circle(600)
printFigure(figure)

如果某個相關(guān)值元組中字段類型一致,需要全部提取溅固,則可以在相關(guān)值前面添加let或var付秕。可以使用如下方式修改Rectangle分支:

switch figure {
case let .Rectangle(width, height):
    print("矩形的寬:\(width) 高: \(height)")
case .Circle(let radius):
    print("圓形的半徑:\(radius)")
}

結(jié)構(gòu)體與類

在面向過程的編程語言中侍郭,結(jié)構(gòu)體用的比較多询吴,但是面向?qū)ο笾螅缭贑++和Objective-C中亮元,結(jié)構(gòu)體已經(jīng)很少使用了猛计。這是應(yīng)為結(jié)構(gòu)體能夠做的事情,類完全可以取而代之爆捞。

而Swift語言卻非常重視結(jié)構(gòu)體奉瘤,把結(jié)構(gòu)體作為實現(xiàn)面向?qū)ο蟮闹匾侄巍wift中的結(jié)構(gòu)體與C++和Objective-C中的結(jié)構(gòu)體有很大的差別,C++和Objective-C中的結(jié)構(gòu)體只能定義一組相關(guān)的成員變量嵌削,而Swift中的結(jié)構(gòu)體不僅可以定義成員變量(屬性)毛好,還可以定義成員方法。因此苛秕,可以把結(jié)構(gòu)體看做是一種輕量級的類肌访。

Swift中的類和結(jié)構(gòu)體非常類似,都具有定義和使用屬性艇劫、方法吼驶、下標(biāo)和構(gòu)造器等面向?qū)ο筇匦裕墙Y(jié)構(gòu)體不具有繼承性店煞,也不具備運行時強(qiáng)制類型轉(zhuǎn)換蟹演、使用析構(gòu)器和使用引用計等能力。

類和結(jié)構(gòu)體定義

Swift中的類和結(jié)構(gòu)體定義的語法也是非常相似的顷蟀。我們可以使用class關(guān)鍵詞定義類酒请,使用struct關(guān)鍵詞定義結(jié)構(gòu)體,它們的語法格式如下:

class 類名 {

定義類的成員

}

struct 結(jié)構(gòu)體名 {

定義結(jié)構(gòu)體的成員

}

從語法格式上看鸣个,Swift中的類和結(jié)構(gòu)體的定義更類似于Java語法羞反,不需要像C++和Objective-C那樣把接口部分和實現(xiàn)部分放到不同的文件中布朦。
示例:

print("---類和結(jié)構(gòu)體定義---")
class Employee {            //定義員工類
    var no : Int = 0        //定義員工編號屬性
    var name : String = ""  //定義員工姓名屬性
    var job : String?       //定義工作屬性
    var salary : Double = 0 //定義薪資屬性
    var dept : Department?  //定義所在部門屬性
}

struct Department {         //定義部門結(jié)構(gòu)體
    var no : Int = 0        //定義部門編號屬性
    var name : String = ""  //定義部門名稱屬性
}

Employee是定義的類,Department是定義的結(jié)構(gòu)體昼窗。
可以通過下列語句實例化:

var emp = Employee()
var dept = Department()

Employee()和Department()是調(diào)用它們的構(gòu)造器實現(xiàn)實例化是趴。

提示:實例化之后會開辟內(nèi)存空間,emp和dept被稱為“實例”澄惊,但只有類實例化的“實例”才能被稱為“對象”唆途。事實上,不僅僅是結(jié)構(gòu)體和類可以實例化掸驱,枚舉肛搬、函數(shù)類型和閉包開辟內(nèi)存空間的過程也可以稱為實例化,結(jié)果也可以叫“實例”亭敢,但不能叫“對象”滚婉。

再談值類型和引用類型

數(shù)據(jù)類型可以分為:值類型和引用類型,這是由賦值或參數(shù)傳遞方式?jīng)Q定的帅刀。值類型就是在賦值或給函數(shù)傳遞參數(shù)時候让腹,創(chuàng)建一個副本,把副本傳遞過去扣溺,這樣在函數(shù)的調(diào)用過程中不會影響原始數(shù)據(jù)骇窍。引用類型就是在賦值或給函數(shù)傳遞參數(shù)的時候,把本身數(shù)據(jù)傳遞過去锥余,這樣在函數(shù)的調(diào)用過程中會影響原始數(shù)據(jù)腹纳。

在眾多的數(shù)據(jù)類型中,只需記浊獭:只有類是引用類型嘲恍,其他類型全部是值類型。即便結(jié)構(gòu)體與類非常相似雄驹,它也是值類型佃牛。值類型還包括整型、浮點型医舆、布爾型俘侠、字符串、元組蔬将、集合和枚舉爷速。

Swift中的引用類型與Java中的引用類型是一樣的,Java中的類也是引用類型霞怀。如果沒有Java經(jīng)驗惫东,可以把引用類型理解為C、C++和Objective-C語言中的指針類型毙石,只不過不需要在引用類型變量或常量前面加星號(*)凿蒜。

示例:

print("--值類型和引用類型--")

var dept = Department()
dept.no = 10
dept.name = "Sales"

var emp = Employee()
emp.no = 1000
emp.name = "Martin"
emp.job = "Salesman"
emp.salary = 1250
emp.dept = dept

func updateDept (inout dept : Department) {
    dept.name = "Research"
}

print("Department更新前:\(dept.name)")
updateDept(&dept)

print("Department更新后:\(dept.name)")

func updateEmp (emp : Employee) {
    emp.job = "Clerk"
}

print("Employee更新前:\(emp.job)")
updateEmp(emp)

print("Employee更新后:\(emp.job)")

對比上面代碼禁谦,說明Employee類是引用類型胁黑,在調(diào)用的時候不用在變量前面添加&符號废封。

引用類型的比較

恒等于(===)和不恒等于(!===)關(guān)系運算符。===用于比較兩個引用是否為同一個實例丧蘸,!===則恰恰相反漂洋,它只能用于引用類型,也就是類的實例力喷。

示例:

print("---引用類型的比較---")

var emp1 = Employee()       //1
emp1.no = 1000
emp1.name = "Martin"
emp1.job = "Salesman"
emp1.salary = 1250

var emp2 = Employee()       //2
emp2.no = 1000
emp2.name = "Martin"
emp2.job = "Salesman"
emp2.salary = 1250

if emp1 === emp2            //3
{
    print("emp1 === emp2")
}

if emp1 === emp1            //4
{
    print("emp1 === emp1")
}

var dept1 = Department()        //5

dept1.no = 10
dept1.name = "Sales"

var dept2 = Department()        //6
dept2.no = 10
dept2.name = "Sales"

if dept1 == dept2 //編譯失敗    //7
{
    print("dept1 === dept2")
}

上述代碼第1行和第2行分別創(chuàng)建了emp1和emp2兩個Employee實例刽漂。在代碼第3行比較emp1和emp2兩個引用是否為一個實例〉苊希可以看到贝咙,比較結(jié)果為False(第3行沒有輸出emp1 === emp2),也就是emp1和emp2兩個引用不是一個實例拂募,即便是它們內(nèi)容完全一樣庭猩,結(jié)果也是False,而第4行的比較結(jié)果為True陈症。如果對于第3行采用==比較蔼水,代碼如下:

if emp1 == emp1
{
    print("emp1 === emp1")
}

答案是有編譯錯誤。==比較要求兩個實例的類型(類录肯、結(jié)構(gòu)體趴腋、枚舉等)必須要在該類型中重寫==運算符,定義相等規(guī)則论咏。同樣的錯誤也會發(fā)生在第7行代碼优炬。

第7行使用==比較dept1和dept2兩個值是否相等,不僅不能比較厅贪,而且還會發(fā)生編譯錯誤蠢护,這在上面已經(jīng)解釋過了。

如果采用恒等于===比較dept1和dept2,代碼如下:

if dept1 === dept2
{
    print("dept1 === dept2")
}

這會發(fā)生編譯錯誤卦溢。===不能比較值類型糊余,而Department結(jié)構(gòu)體是值類型,因此不能使用===比較单寂。


類型嵌套

Swift語言中的類贬芥、結(jié)構(gòu)體和枚舉可以進(jìn)行嵌套,即在某一類型的{}內(nèi)部定義類宣决。這種類型嵌套在Java中稱為內(nèi)部類蘸劈,在C#中稱為嵌套類,它們的形式和設(shè)計目的都是類似的尊沸。

類型嵌套的優(yōu)點是能夠訪問它外部的成員(包括方法威沫、屬性和其他的嵌套類型)贤惯,嵌套還可以有多個層次。

示例:

print("---類型嵌套---")

class Employee {
    var no : Int = 0
    var name : String = ""
    var job : String = ""
    var salary : Double = 0
    var dept : Department = Department()
    
    var day : WeekDays = WeekDays.Friday
    
    struct Department {
        var no : Int = 10
        var name : String = "SALES"
    }
    
    enum WeekDays {
        case Monday
        case Tuesday
        case Wednesday
        case Thursday
        case Friday
        
        struct Day {
            static var message : String = "Today is ..."
        }
    }
    
}

var emp = Employee()
print(emp.dept.name)
print(emp.day)

let friday = Employee.WeekDays.Friday
if emp.day == friday {
    print("相等")
}
print(Employee.WeekDays.Day.message)

類型嵌套便于我們訪問外部類的成員棒掠,但它會使程序結(jié)構(gòu)變得不清楚孵构,使程序的可讀性變差。


可選類型與可選鏈

可選類型

有時使用一個變量或常量烟很,它保存的值可能有也可能沒有颈墅。示例代碼:

print("---可選類型---")

func divide(n1 : Int, n2 : Int) -> Double? {
    if n2 == 0 {
        return nil
    }
    
    return Double(n1) / Double(n2)
    
}
let result : Double? = divide(100, n2: 200)

可選綁定

可選類型可以用于判斷,如下代碼:

print("---可選綁定---")

if let result2 : Double? = divide(100, n2: 0) {
    print("Success.")
} else {
    print("failure.")
}

輸出結(jié)果為failure.

這種可選類型在if或while語句中賦值并進(jìn)行判斷的寫法雾袱,叫做可選綁定恤筛。

強(qiáng)制拆封

如果我們能確定可選類型一定有值,那么在讀取它的時候芹橡,可以在可選類型的后面加一個感嘆號(!)來獲取該值毒坛。這種感嘆號的表示方式稱為可選值的強(qiáng)制拆封(forced unwrapping)。如下代碼:

print("---強(qiáng)制拆封---")

let result1 : Double? = divide(100, n2: 200)
print(result1)

print(result1!)//語句中的result1就進(jìn)行了強(qiáng)制拆封

隱式拆封

為了能夠方便地訪問可選類型林说,可以將可選類型后面的問號(?)換成感嘆號(!)煎殷,這種可選類型在拆封時變量或常量后面不加感嘆號(!)的表示方式成為隱式拆封。如下代碼:

print("--隱私拆封---")

let result3 : Double! = divide(100, n2: 200)
print(result3)

在變量或常量聲明的時候述么,數(shù)據(jù)類型Double后面跟的是感嘆號(!)而不是問號(?)蝌数,在拆封的時候,變量或常量后面不用加感嘆號(!)度秘,這就是隱式拆封顶伞。隱式拆封的變量或常量使用起來就像普通變量或常量一樣,也可以把它看成是普通的變量或常量剑梳。


可選鏈

示例代碼:

print("--可選鏈---")

class Employee {
    var no : Int = 0
    var name : String = "Tony"
    var job : String?
    var salary : Double = 0
    var dept : Department = Department()
}

class Department {
    var no : Int = 10
    var name : String = "SALES"
    var comp : Company = Company()
}

class Company {
    var no : Int = 1000
    var name : String = "EOrient"
}

var emp = Employee()
print(emp.dept.comp.name)

Employee通過dept屬性與Department關(guān)聯(lián)唆貌,Department通過comp屬性與Company關(guān)聯(lián)。
通過代碼emp.dept.comp.name可以引用到Company實例垢乙,形成一個引用的鏈條锨咙,但是這個“鏈條”任何一個環(huán)節(jié)“斷裂”(為nil)都無法引用到最后的目標(biāo)(Company實例)。

var dept : Department = Department()是使用Department()構(gòu)造器實例化dept屬性的追逮,這說明給定一個Employee實例酪刀,一定會有一個Department與其關(guān)聯(lián)。但是現(xiàn)實世界并非如此钮孵,這種關(guān)聯(lián)關(guān)系有可能有值骂倘,也有可能沒有值,我們需要使用可選類型(Department?)聲明dept實例巴席。

修改代碼如下:

class Employee {
    var no : Int = 0
    var name : String = "Tony"
    var job : String?
    var salary : Double = 0
    var dept : Department?
}


class Department {
    var no : Int = 10
    var name : String = "SALES"
    var comp : Company?
}

class Company {
    var no : Int = 1000
    var name : String = "EOrient"
}

var dept : Department?代碼聲明dept為可選類型历涝,代碼var comp : Company?聲明comp為可選類型,那么原來的引用方式emp.dept.comp.name已經(jīng)不能應(yīng)對可選類型了。之前介紹過可選類型的引用荧库,可以使用感嘆號(!)進(jìn)行強(qiáng)制拆封堰塌,代碼修改如下:

print(emp.dept!.comp!.name)

但是強(qiáng)制拆封有一個弊端,如果可選鏈中某個環(huán)節(jié)為nil分衫,將會導(dǎo)致代碼運行時錯誤场刑。可以采用更加“溫柔”的引用方式丐箩,使用問號(?)來代替原來感嘆號(!)的位置摇邦。如下所示:

print(emp.dept?.comp?.name)

問號(?)表示引用的時候,如果某個環(huán)節(jié)為nil屎勘,它不會拋出錯誤,而是會把nil返回給引用者居扒。這種由問號(?)引用可選類型的方式就是可選鏈概漱。

可選鏈?zhǔn)且环N“溫柔”的引用方式,它的引用目標(biāo)不僅僅是屬性喜喂,還可以是方法瓤摧、下標(biāo)和嵌套類型等。

具有嵌套類型的示例:

class Employee {
    var no : Int = 0
    var name : String = ""
    var job : String = ""
    var salary : Double = 0
    var dept : Department?
    
    struct Department {
        var no : Int = 10
        var name : String = "SALES"
    }
    
}

var emp = Employee()
print(emp.dept?.name)

代碼var dept : Department?定義可選類型Department?的屬性dept玉吁,Department是嵌套結(jié)構(gòu)體類型照弥。print(emp.dept?.name)采用可選鏈方式引用。輸出結(jié)果為nil进副,這是因為emp.dept環(huán)節(jié)為nil这揣。如果將代碼var dept : Department?修改一下:

var dept : Department? = Department()

則輸出結(jié)果為SALES。這說明可選鏈可以到達(dá)目標(biāo)name影斑。

1.可選類型中的問號(?)

聲明這個類型是可選類型给赞,訪問這種類型的變量和常量時要使用感嘆號(!),下列代碼是強(qiáng)制拆封:

let result1 : Double? = divide(100, 200)
print(result1!)

2.可選類型中的感嘆號(!)

聲明這個類型也是可選類型,但是訪問這種類型的變量或常量時可以不使用感嘆號(!)矫户,下列代碼是隱式拆封:

let result3 : Double? = divide(100, 200)
print(result3)

3.可選鏈中的感嘆號(!)

多個對象具有關(guān)聯(lián)關(guān)系片迅,當(dāng)從一個對象引用另外對象的方式、屬性和下標(biāo)等成員時就會形成引用連皆辽,由于這個“鏈條”某些環(huán)節(jié)可能有值柑蛇,也可能沒有值,因此需要采用如下方式訪問:

emp.dept!.comp!.name

4.可選鏈中的問號(?)

在可選鏈中使用感嘆號(!)訪問時驱闷,一旦“鏈條”某些環(huán)節(jié)沒有值耻台,程序就會發(fā)生異常,于是我們把感嘆號(!)改為問號(?)
遗嗽,代碼如下所示:

emp.dept?.comp?.name

這樣某些環(huán)節(jié)沒有值的時候返回nil粘我,程序不會發(fā)生異常。


訪問限定

作為一種面向?qū)ο蟮恼Z言封裝性是不可缺少的,Swift語言在正式版中增加了訪問控制征字,這樣一來Swift語言就可以實現(xiàn)封裝特性了都弹。由于在Swift語言中類、結(jié)構(gòu)體和枚舉類型都具有面向?qū)ο蟮奶匦猿捉虼薙wift語言的封裝就變得比較復(fù)雜畅厢。


訪問范圍

訪問范圍主要有兩個: 模塊和源文件。

模塊是指一個應(yīng)用程序包或一個框架氮昧。在Swift中框杜,可以用import關(guān)鍵字將模塊引入到自己的工程中。應(yīng)用程序包是可執(zhí)行的袖肥,其內(nèi)部包含了很多Swift文件以及其他文件咪辱。

框架也是很多Swift文件及其他文件的集合,但是應(yīng)用程序包不同的是椎组,它編譯的結(jié)果是不可以執(zhí)行文件油狂。

源文件指的是Swift中的.swift文件,編譯之后它被包含在應(yīng)用程序包或框架中寸癌,通常一個源文件包含一個面向?qū)ο箢愋停愖辍⒔Y(jié)構(gòu)體和枚舉),在這些類型中又包含函數(shù)蒸苇、屬性等磷蛹。


訪問級別

Swift提供了3種不同訪問級別,對應(yīng)的訪問修飾符為:public溪烤、internal和private味咳。這些訪問修飾符可以修飾類、結(jié)構(gòu)體氛什、枚舉等面向?qū)ο蟮念愋洼汉€可以修飾變量、常量枪眉、下標(biāo)捺檬、元組、函數(shù)贸铜、屬性等內(nèi)容堡纬。

提示:為了便于描述,我們把類蒿秦、結(jié)構(gòu)體烤镐、枚舉、變量棍鳖、常量炮叶、下標(biāo)碗旅、元組、函數(shù)镜悉、屬性等內(nèi)容統(tǒng)一稱為“實體”祟辟。

  • public 可以訪問自己模塊中的任何public實體。如果使用import語句引入其他模塊侣肄,可以訪問其他模塊中的public實體旧困。

  • internal 只能訪問自己模塊的任何internal實體,不能訪問其他模塊中的internal實體稼锅。internal可以省略吼具,換句話說,默認(rèn)訪問限定是internal

  • private 只能在當(dāng)前源文件中使用的實體矩距,稱為私有實體拗盒。使用private修飾,可以用作隱藏某些功能的實現(xiàn)細(xì)節(jié)剩晴。

使用訪問修飾符的示例代碼如下:

print("--使用訪問修飾符示例代碼---")

public class PublicClass {}

internal class InternalClass {}

private class PrivateClass {}

public var intPublicVariable = 0
let intInternalConstant = 0//internal訪問級別
private func intPrivateFunction()

使用訪問級別最佳實踐

1.統(tǒng)一性原則

  • 原則1:如果一個類型(類锣咒、結(jié)構(gòu)體、枚舉)定義為internal或private赞弥,那么類型聲明的變量或常量不能使用public訪問級別。因為public的變量或常量可以被任何人訪問趣兄,而internal或private的類型不可以绽左。

代碼:

print("--原則1--")

private class Employee {
    var no : Int = 0
    var name : String = ""
    var job : String?
    var salary : Double = 0
    var dept : Department?
}

internal struct Department {
    var no : Int = 0
    var name : String = ""
}

public let emp = Employee()//編譯錯誤

public var dept = Department()//編譯錯誤

2.設(shè)計原則

如果編寫的是應(yīng)用程序,應(yīng)用程序包中的所有Swift文件和其中定義的實體艇潭,都是供本應(yīng)用使用的拼窥,而不是提供其他模塊使用,那么就不用設(shè)置訪問級別了蹋凝,即使用默認(rèn)的訪問級別鲁纠。

如果開發(fā)的是框架,框架編譯的文件不能獨立運行鳍寂,因此它天生就是給別人使用的改含,這種情況下要詳細(xì)設(shè)計其中的Swift文件和實體的訪問級別,讓別人使用的可以設(shè)定為public迄汛,不想讓別人看到的可以設(shè)定為internal或private捍壤。

3.元組類型的訪問級別
元組類型的訪問級別遵循元組中字段最低級的訪問級別。代碼如下:

print("---元組類型的訪問級別---")

private class Employee {
    var no : Int = 0
    var name : String = ""
    var job : String?
    var salary : Double = 0
    var dept : Department?
}

struct Department {
    var no : Int = 0
    var name : String = ""
}

private let emp = Employee()
var dept = Department()

private var student1 = (dept, emp)

private var student1 = (dept, emp)定義了元組student1鞍爱,其中的字段dept和emp的最低訪問級別是private鹃觉,所以student1訪問級別也是private,這也符合統(tǒng)一性原則睹逃。

4.枚舉類型的訪問級別

枚舉中成員的訪問級別繼承自該枚舉盗扇,因此不能為枚舉中的成員指定訪問級別。示例代碼如下:

print("---枚舉類型的訪問級別---")

public enum WeekDays {
    case Monday
    case Tuesday
    case Wednesday
    case Thursday
    case Friday
}

由于WeekDays枚舉類型是public訪問級別,因而它的成員也是public級別疗隶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者

  • 序言:七十年代末佑笋,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子抽减,更是在濱河造成了極大的恐慌允青,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卵沉,死亡現(xiàn)場離奇詭異颠锉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)史汗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門琼掠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人停撞,你說我怎么就攤上這事瓷蛙。” “怎么了戈毒?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵艰猬,是天一觀的道長。 經(jīng)常有香客問我埋市,道長冠桃,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任道宅,我火速辦了婚禮食听,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘污茵。我一直安慰自己樱报,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布泞当。 她就那樣靜靜地躺著迹蛤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪零蓉。 梳的紋絲不亂的頭發(fā)上笤受,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音敌蜂,去河邊找鬼箩兽。 笑死,一個胖子當(dāng)著我的面吹牛章喉,可吹牛的內(nèi)容都是我干的汗贫。 我是一名探鬼主播身坐,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼落包!你這毒婦竟也來了部蛇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤咐蝇,失蹤者是張志新(化名)和其女友劉穎涯鲁,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體有序,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡抹腿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了旭寿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片警绩。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盅称,靈堂內(nèi)的尸體忽然破棺而出肩祥,到底是詐尸還是另有隱情,我是刑警寧澤缩膝,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布混狠,位于F島的核電站,受9級特大地震影響疾层,放射性物質(zhì)發(fā)生泄漏檀蹋。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一云芦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贸桶,春花似錦舅逸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至水醋,卻和暖如春旗笔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拄踪。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工蝇恶, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惶桐。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓撮弧,卻偏偏與公主長得像潘懊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子贿衍,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容