欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Swift教程之類與結(jié)構(gòu)詳解

 更新時(shí)間:2015年01月12日 14:21:32   投稿:junjie  
這篇文章主要介紹了Swift教程之類與結(jié)構(gòu)詳解,本文講解了類和結(jié)構(gòu)的異同、結(jié)構(gòu)和枚舉類型是數(shù)值類型、類是引用類型、如何選擇使用類還是結(jié)構(gòu)、集合類型的賦值和復(fù)制操作等內(nèi)容,需要的朋友可以參考下

類與結(jié)構(gòu)是編程人員在代碼中會(huì)經(jīng)常用到的代碼塊。在類與結(jié)構(gòu)中可以像定義常量,變量和函數(shù)一樣,定義相關(guān)的屬性和方法以此來(lái)實(shí)現(xiàn)各種功能。

和其它的編程語(yǔ)言不太相同的是,Swift不需要單獨(dú)創(chuàng)建接口或者實(shí)現(xiàn)文件來(lái)使用類或者結(jié)構(gòu)。Swift中的類或者結(jié)構(gòu)可以在單文件中直接定義,一旦定義完成后,就能夠被直接其它代碼使用。

注意:一個(gè)類的實(shí)例一般被視作一個(gè)對(duì)象,但是在Swift中,類與結(jié)構(gòu)更像是一個(gè)函數(shù)方法,在后續(xù)的章節(jié)中更多地是講述類和結(jié)構(gòu)的功能性。

1、類和結(jié)構(gòu)的異同

類和結(jié)構(gòu)有一些相似的地方,它們都可以:

定義一些可以賦值的屬性;

定義具有功能性的方法

定義下標(biāo),使用下標(biāo)語(yǔ)法

定義初始化方法來(lái)設(shè)置初始狀態(tài)

在原實(shí)現(xiàn)方法上的可擴(kuò)展性

根據(jù)協(xié)議提供某一特定類別的基本功能

更多內(nèi)容可以閱讀:屬性,方法,下標(biāo),初始化,擴(kuò)展和協(xié)議等章節(jié)

類還有一些結(jié)構(gòu)不具備的特性:

類的繼承性

對(duì)類實(shí)例實(shí)時(shí)的類型轉(zhuǎn)換

析構(gòu)一個(gè)類的實(shí)例使之釋放空間

引用計(jì)數(shù),一個(gè)類實(shí)例可以有多個(gè)引用

更多內(nèi)容可以閱讀:繼承,類型轉(zhuǎn)換,初始化自動(dòng)引用計(jì)數(shù)

注意:結(jié)構(gòu)每次在代碼中傳遞時(shí)都是復(fù)制了一整個(gè),所以不要使用引用計(jì)數(shù)

定義語(yǔ)法

類和結(jié)構(gòu)擁有相似的定義語(yǔ)法,使用class關(guān)鍵詞定義一個(gè)類,struct關(guān)鍵詞定義結(jié)構(gòu)。每個(gè)定義都由一對(duì)大括號(hào)包含:

復(fù)制代碼 代碼如下:
 
class SomeClass {
// class definition goes here
}
struct SomeStructure {
// structure definition goes here
}

注意:在定義類和結(jié)構(gòu)時(shí),一般使用UpperCamelCase命名法來(lái)定義類和結(jié)構(gòu)的名稱,比如SomeClass和SomeStructure,這樣也符合Swift其它類型的標(biāo)準(zhǔn)。而給屬性和方法命名時(shí),一般時(shí)候lowerCamelCase命名法,比如frameRate和incrementCount等。
下面是一個(gè)結(jié)構(gòu)和一個(gè)類的定義示例:

復(fù)制代碼 代碼如下:
 
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = falsevar
frameRate = 0.0
var name: String?
}

上面的例子首先定義了一個(gè)叫Resolution的結(jié)構(gòu),用來(lái)描述一個(gè)像素顯示的分辨率,它有兩個(gè)屬性分別叫width和height。這兩個(gè)屬性被默認(rèn)定義為Int類型,初始化為0.

之后定義了一個(gè)叫VideoMode的類,為視頻顯示的顯示方式。這個(gè)類有四個(gè)屬性,第一個(gè)屬性resolution本身又是一個(gè)結(jié)構(gòu),然后是另外兩個(gè)屬性。最后一個(gè)屬性用到了可選字符串類型String?,表示這個(gè)屬性可以存在,或者不存在為nil。

類和結(jié)構(gòu)的實(shí)例

上面的兩個(gè)定義僅僅是定義了結(jié)構(gòu)Resolution和類VideoMode的整體樣式,它們本身不是一個(gè)特定的分辨率或者顯示方式,這時(shí)候就需要實(shí)例化這個(gè)結(jié)構(gòu)和類。

實(shí)例化的語(yǔ)法相似:

復(fù)制代碼 代碼如下:

let someResolution = Resolution()
let someVideoMode = VideoMode()

類和結(jié)構(gòu)都使用實(shí)例語(yǔ)法來(lái)完成實(shí)例化。最簡(jiǎn)單的實(shí)例語(yǔ)法就是用兩個(gè)括號(hào)()完成。在這種情況下定義的實(shí)例中的屬性都會(huì)完成默認(rèn)初始化。更多內(nèi)容可以參考初始化一章。

訪問(wèn)屬性

使用.語(yǔ)法就可以方便地訪問(wèn)一個(gè)實(shí)例的屬性。在.語(yǔ)法中,在實(shí)例名之后加上(.)再加上屬性名即可,不需要空格:

復(fù)制代碼 代碼如下:

println("The width of someResolution is \(someResolution.width)")
// prints "The width of someResolution is 0"

在這個(gè)例子中,someResolution.width表示someResolution的width屬性,返回了它的初始值0

也可以使用.語(yǔ)法連續(xù)地獲取屬性的屬性,比如VideoMode中resolution屬性的width屬性

復(fù)制代碼 代碼如下:
 
println("The width of someVideoMode is \(someVideoMode.resolution.width)")
// prints "The width of someVideoMode is 0"

使用這種方法不僅可以訪問(wèn),也可以賦值:

復(fù)制代碼 代碼如下:
 
someVideoMode.resolution.width = 1280
println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
// prints "The width of someVideoMode is now 1280"

注意:和Objective-C不同,Swift能夠直接設(shè)置一個(gè)結(jié)構(gòu)屬性的子屬性,就像上面這個(gè)例子一樣。

結(jié)構(gòu)類型的成員初始化方法

每個(gè)結(jié)構(gòu)都有一個(gè)成員初始化方法,可以在初始化的時(shí)候通過(guò)使用屬性名稱來(lái)指定每一個(gè)屬性的初始值:

復(fù)制代碼 代碼如下:
 
let vga = Resolution(width: 640, height: 480)

但是和結(jié)構(gòu)不同,類實(shí)例不能夠使用成員初始化方法,在初始化一章有專門(mén)的介紹。

2、結(jié)構(gòu)和枚舉類型是數(shù)值類型

數(shù)值類型是說(shuō)當(dāng)它被賦值給一個(gè)常量或者變量,或者作為參數(shù)傳遞給函數(shù)時(shí),是完整地復(fù)制了一個(gè)新的數(shù)值,而不是僅僅改變了引用對(duì)象。

事實(shí)上讀到這里你已經(jīng)在前面幾章見(jiàn)過(guò)數(shù)值類型了,所有Swift中的基礎(chǔ)類型-整型,浮點(diǎn)型,布爾類型,字符串,數(shù)組和字典都是數(shù)值類型。它們也都是由結(jié)構(gòu)來(lái)實(shí)現(xiàn)的。

在Swift中所有的結(jié)構(gòu)和枚舉類型都是數(shù)值類型。這意味這你實(shí)例化的每個(gè)結(jié)構(gòu)和枚舉,其包含的所有屬性,都會(huì)在代碼中傳遞的時(shí)候被完整復(fù)制。

下面的這個(gè)例子可以說(shuō)明這個(gè)特性:

復(fù)制代碼 代碼如下:
 
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd

聲明了一個(gè)常量hd,是Resolution的實(shí)例化,寬度是1920,高度是1080,然后聲明了一個(gè)變量cinema,和hd相同。這個(gè)時(shí)候表明,cinema和hd是兩個(gè)實(shí)例,雖然他們的寬度都是1920,高度都是1080。

如果把cinema的寬度更改為2048,hd的寬度不會(huì)變化,依然是1920

復(fù)制代碼 代碼如下:
 
cinema.width = 2048
println("cinema is now \(cinema.width) pixels wide")
// prints "cinema is now 2048 pixels wide"
println("hd is still \(hd.width) pixels wide")
// prints "hd is still 1920 pixels wide"

這表明當(dāng)hd被賦值給cinema時(shí),是完整地復(fù)制了一個(gè)全新的Resolution結(jié)構(gòu)給cinema,所以當(dāng)cinema的屬性被修改時(shí),hd的屬性不會(huì)變化。

下面的例子演示的是枚舉類型:

復(fù)制代碼 代碼如下:

enum CompassPoint {
case North, South, East, West
}
var currentDirection = CompassPoint.West
let rememberedDirection = currentDirection
currentDirection = .East
if rememberedDirection == .West {
println("The remembered direction is still .West")
}
// prints "The remembered direction is still .West"

盡管經(jīng)過(guò)幾次賦值,rememberedDirection依然沒(méi)有變化,這是因?yàn)樵诿恳淮钨x值過(guò)程中,都是將數(shù)值類型完整地復(fù)制了過(guò)來(lái)。

3、類是引用類型

和數(shù)值類型不同引用類型不會(huì)復(fù)制整個(gè)實(shí)例,當(dāng)它被賦值給另外一個(gè)常量或者變量的時(shí)候,而是會(huì)建立一個(gè)和已有的實(shí)例相關(guān)的引用來(lái)表示它。

下面是引用的示例,VideoMode被定義為一個(gè)類:

復(fù)制代碼 代碼如下:
 
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0

分別將這個(gè)實(shí)例tenEighty的四個(gè)屬性初始化,然后tenEighty被賦值給了另外一個(gè)叫alsoTenEighty的常量,然后alsoTenEighty的frameRate被修改了

復(fù)制代碼 代碼如下:

let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0

由于類是一個(gè)引用類型,所以tenEighty和alsoTenEighty實(shí)際上是同一個(gè)實(shí)例,僅僅只是使用了不同的名稱而已,我們通過(guò)檢查frameRate可以證明這個(gè)問(wèn)題:

復(fù)制代碼 代碼如下:
 
println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// prints "The frameRate property of tenEighty is now 30.0"

注意到tenEighty和alsoTenEighty是被定義為常量的,而不是變量。但是我們還是可以改變他們的屬性值,這是因?yàn)樗鼈儽旧韺?shí)際上沒(méi)有改變,它們并沒(méi)有保存這個(gè)VideoMode的實(shí)例,僅僅只是引用了一個(gè)VideoMode實(shí)例,而我們修改的也是它們引用的實(shí)例中的屬性。

特征操作

因?yàn)轭愂且妙愋?,那么就可能存在多個(gè)常量或者變量只想同一個(gè)類的實(shí)例(這對(duì)于數(shù)值類型的結(jié)構(gòu)和枚舉是不成立的)。

可以通過(guò)如下兩個(gè)操作來(lái)判斷兩個(gè)常量或者變量是否引用的是同一個(gè)類的實(shí)例:

相同的實(shí)例(===)

不同的實(shí)例(!==)

使用這些操作可以檢查:

復(fù)制代碼 代碼如下:
 
if tenEighty === alsoTenEighty {
println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
// prints "tenEighty and alsoTenEighty refer to the same Resolution instance."

注意是相同的實(shí)例判斷使用三個(gè)連續(xù)的等號(hào),這和相等(兩個(gè)等號(hào))是不同的

實(shí)例相同表示的是兩個(gè)變量或者常量所引用的是同一個(gè)類的實(shí)例

相等是指兩個(gè)實(shí)例在數(shù)值上的相等,或者相同。

當(dāng)你定義一個(gè)類的時(shí)候,就需要說(shuō)明什么樣的時(shí)候是兩個(gè)類相等,什么時(shí)候是兩個(gè)類不相等。更多內(nèi)容可以從相等操作一章中獲得。

指針

如果你有C,C++或者Objective-C的編程經(jīng)驗(yàn),你一定知道在這些語(yǔ)言中使用指針來(lái)引用一個(gè)內(nèi)存地址。Swift中引用一個(gè)實(shí)例的常量或變量跟C中的指針類似,但是不是一個(gè)直接指向內(nèi)存地址的指針,也不需要使用*記號(hào)表示你正在定義一個(gè)引用。Swift中引用和其它變量,常量的定義方法相同。

4、如何選擇使用類還是結(jié)構(gòu)

在代碼中可以選擇類或者結(jié)構(gòu)來(lái)實(shí)現(xiàn)你所需要的代碼塊,完成相應(yīng)的功能。但是結(jié)構(gòu)實(shí)例傳遞的是值,而類實(shí)例傳遞的是引用。那么對(duì)于不同的任務(wù),應(yīng)該考慮到數(shù)據(jù)結(jié)構(gòu)和功能的需求不同,從而選擇不同的實(shí)例。

一般來(lái)說(shuō),下面的一個(gè)或多個(gè)條件滿足時(shí),應(yīng)當(dāng)選擇創(chuàng)建一個(gè)結(jié)構(gòu):

結(jié)構(gòu)主要是用來(lái)封裝一些簡(jiǎn)單的數(shù)據(jù)值

當(dāng)賦值或者傳遞的時(shí)候更希望這些封裝的數(shù)據(jù)被賦值,而不是被引用過(guò)去

所有被結(jié)構(gòu)存儲(chǔ)的屬性本身也是數(shù)值類型

結(jié)構(gòu)不需要被另外一個(gè)類型繼承或者完成其它行為

一些比較好的使用結(jié)構(gòu)的例子:

一個(gè)幾何形狀的尺寸,可能包括寬度,高度或者其它屬性,每個(gè)屬性都是Double類型的

一個(gè)序列的對(duì)應(yīng)關(guān)系,可能包括開(kāi)始start和長(zhǎng)度length屬性,每個(gè)屬性都是Int類型的

3D坐標(biāo)系中的一個(gè)點(diǎn),包括x,y和z坐標(biāo),都是Double類型

在其它情況下,類會(huì)是更好的選擇。也就是說(shuō)一般情況下,自定義的一些數(shù)據(jù)結(jié)構(gòu)一般都會(huì)被定義為類。

5、集合類型的賦值和復(fù)制操作

Swift中,數(shù)組Array和字典Dictionary是用結(jié)構(gòu)來(lái)實(shí)現(xiàn)的,但是數(shù)組與字典和其它結(jié)構(gòu)在進(jìn)行賦值或者作為參數(shù)傳遞給函數(shù)的時(shí)候有一些不同。

并且數(shù)組和字典的這些操作,又與Foundation中的NSArray和NSDictionary不同,它們是用類來(lái)實(shí)現(xiàn)的。

注意:下面的小節(jié)將會(huì)介紹數(shù)組,字典,字符串等的復(fù)制操作。這些復(fù)制操作看起來(lái)都已經(jīng)發(fā)生,但是Swift只會(huì)在確實(shí)需要復(fù)制的時(shí)候才會(huì)完整復(fù)制,從而達(dá)到最優(yōu)的性能。

字典的賦值和復(fù)制操作

每次將一個(gè)字典Dictionary類型賦值給一個(gè)常量或者變量,或者作為參數(shù)傳遞給函數(shù)時(shí),字典會(huì)在賦值或者函數(shù)調(diào)用時(shí)才會(huì)被復(fù)制。這個(gè)過(guò)程在上面的小節(jié):結(jié)構(gòu)和枚舉是數(shù)值類型中描述了。

如果字典中的鍵值是數(shù)值類型(結(jié)構(gòu)或者枚舉),它們?cè)谫x值的時(shí)候會(huì)同時(shí)被復(fù)制。相反,如果是引用類型(類或者函數(shù)),引用本身將會(huì)被復(fù)制,而不是類實(shí)例或者函數(shù)本身。字典的這種復(fù)制方式和結(jié)構(gòu)相同。

下面的例子演示的是一個(gè)叫ages的字典,存儲(chǔ)了一些人名和年齡的對(duì)應(yīng)關(guān)系,當(dāng)賦值給copiedAges的時(shí)候,里面的數(shù)值同時(shí)被完整復(fù)制。當(dāng)改變復(fù)制了的數(shù)值的時(shí)候,原有的數(shù)值不會(huì)變化,如下例子:

復(fù)制代碼 代碼如下:
 
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages

這個(gè)字典的鍵是字符串String類型,值是Int類型,都是數(shù)值類型,那么在賦值的時(shí)候都會(huì)被完整復(fù)制。

復(fù)制代碼 代碼如下:

copiedAges["Peter"] = 24
println(ages["Peter"])
// prints "23"

數(shù)組的賦值和復(fù)制操作

和字典Dictionary類型比起來(lái),數(shù)組Array的賦值和復(fù)制操作就更加復(fù)雜。Array類型和C語(yǔ)言中的類似,僅僅只會(huì)在需要的時(shí)候才會(huì)完整復(fù)制數(shù)組的值。

如果將一個(gè)數(shù)組賦值給一個(gè)常量或者變量,或者作為一個(gè)參數(shù)傳遞給函數(shù),復(fù)制在賦值和函數(shù)調(diào)用的時(shí)候并不會(huì)發(fā)生。這兩個(gè)數(shù)組將會(huì)共享一個(gè)元素序列,如果你修改了其中一個(gè),另外一個(gè)也將會(huì)改變。

對(duì)于數(shù)組來(lái)說(shuō),復(fù)制只會(huì)在你進(jìn)行了一個(gè)可能會(huì)修改數(shù)組長(zhǎng)度操作時(shí)才會(huì)發(fā)生。包括拼接,添加或者移除元素等等。當(dāng)復(fù)制實(shí)際發(fā)生的時(shí)候,才會(huì)像字典的賦值和復(fù)制操作一樣。

下面的例子演示了數(shù)組的賦值操作:

復(fù)制代碼 代碼如下:
 
var a = [1, 2, 3]
var b = a
var c = a

數(shù)組a被賦值給了b和c,然后輸出相同的下標(biāo)會(huì)發(fā)現(xiàn):

復(fù)制代碼 代碼如下:
 
println(a[0])
// 1
println(b[0])
// 1
println(c[0])
// 1

如果改變a中的某個(gè)值,會(huì)發(fā)現(xiàn)b和c中的數(shù)值也會(huì)跟著改變,因?yàn)橘x值操作沒(méi)有改變數(shù)組的長(zhǎng)度:

復(fù)制代碼 代碼如下:
 
a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42

但是,如果在a中添加一個(gè)新的元素,那么就改變了數(shù)組的長(zhǎng)度,這個(gè)時(shí)候就會(huì)發(fā)生實(shí)際的復(fù)制操作。如果再改變a中元素的值,b和c中的元素將不會(huì)發(fā)生改變:

復(fù)制代碼 代碼如下:

a.append(4)
a[0] = 777
println(a[0])
// 777
println(b[0])
// 42
println(c[0])
// 42

設(shè)置數(shù)組是唯一的

如果可以在對(duì)數(shù)組進(jìn)行修改前,將它設(shè)置為唯一的就最好了。我們可以通過(guò)使用unshare方法來(lái)將數(shù)組自行拷貝出來(lái),成為一個(gè)唯一的實(shí)體。

如果多個(gè)變量引用了同一個(gè)數(shù)組,可以使用unshare方法來(lái)完成一次“獨(dú)立”

復(fù)制代碼 代碼如下:

b.unshare()

這時(shí)候如果再修改b的值,c的值也不會(huì)再受影響

復(fù)制代碼 代碼如下:
 
b[0] = -105
println(a[0])
// 777
println(b[0])
// -105
println(c[0])
// 42

檢查兩個(gè)數(shù)組時(shí)候共用了相同的元素

使用實(shí)例相等操作符來(lái)判斷兩個(gè)數(shù)組是否共用了元素(===和!===)

下面這個(gè)例子演示的就是判斷是否共用元素:

復(fù)制代碼 代碼如下:
 
if b === c {
println("b and c still share the same array elements.")
} else {
println("b and c now refer to two independent sets of array elements.")
}
// prints "b and c now refer to two independent sets of array elements."

也可以使用這個(gè)操作來(lái)判斷兩個(gè)子數(shù)組是否有共用的元素:

復(fù)制代碼 代碼如下:
 
if b[0...1] === b[0...1] {
println("These two subarrays share the same elements.")
} else {
println("These two subarrays do not share the same elements.")
}
// prints "These two subarrays share the same elements."

強(qiáng)制數(shù)組拷貝

通過(guò)調(diào)用數(shù)組的copy方法來(lái)完成強(qiáng)制拷貝。這個(gè)方法將會(huì)完整復(fù)制一個(gè)數(shù)組到新的數(shù)組中。

下面的例子中這個(gè)叫names的數(shù)組會(huì)被完整拷貝到copiedNames中去。

復(fù)制代碼 代碼如下:
 
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = names.copy()

通過(guò)改變copiedNames的值可以驗(yàn)證,數(shù)組已經(jīng)被完整拷貝,不會(huì)影響到之前的數(shù)組:

復(fù)制代碼 代碼如下:
 
copiedNames[0] = "Mo"
println(names[0])
// prints "Mohsen"

注意:如果你不確定你需要的數(shù)組是否是獨(dú)立的,那么僅僅使用unshare就可以了。而copy方法不管當(dāng)前是不是獨(dú)立的,都會(huì)完整拷貝一次,哪怕這個(gè)數(shù)組已經(jīng)是unshare的了。

相關(guān)文章

最新評(píng)論