在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 類和結(jié)構(gòu)體
方法 - Methods
關(guān)于 Swift
下標(biāo)腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動(dòng)引用計(jì)數(shù)
繼承(Inheritance)
擴(kuò)展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級(jí)運(yùn)算符
訪問控制
基本運(yùn)算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

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

類和結(jié)構(gòu)體是人們構(gòu)建代碼所用的一種通用且靈活的構(gòu)造體。為了在類和結(jié)構(gòu)體中實(shí)現(xiàn)各種功能,我們必須要嚴(yán)格按照常量、變量以及函數(shù)所規(guī)定的語法規(guī)則來定義屬性和添加方法。

與其他編程語言所不同的是,Swift 并不要求你為自定義類和結(jié)構(gòu)去創(chuàng)建獨(dú)立的接口和實(shí)現(xiàn)文件。你所要做的是在一個(gè)單一文件中定義一個(gè)類或者結(jié)構(gòu)體,系統(tǒng)將會(huì)自動(dòng)生成面向其它代碼的外部接口。

注意: 通常一個(gè)的實(shí)例被稱為對(duì)象。然而在Swift 中,類和結(jié)構(gòu)體的關(guān)系要比在其他語言中更加的密切,本章中所討論的大部分功能都可以用在類和結(jié)構(gòu)體上。因此,我們會(huì)主要使用實(shí)例而不是對(duì)象

類和結(jié)構(gòu)體對(duì)比

Swift 中類和結(jié)構(gòu)體有很多共同點(diǎn)。共同處在于:

  • 定義屬性用于存儲(chǔ)值
  • 定義方法用于提供功能
  • 定義附屬腳本用于訪問值
  • 定義構(gòu)造器用于生成初始化值
  • 通過擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)的功能
  • 符合協(xié)議以對(duì)某類提供標(biāo)準(zhǔn)功能

更多信息請(qǐng)參見 屬性方法,下標(biāo)腳本,初始過程擴(kuò)展,和協(xié)議。

與結(jié)構(gòu)體相比,類還有如下的附加功能:

  • 繼承允許一個(gè)類繼承另一個(gè)類的特征
  • 類型轉(zhuǎn)換允許在運(yùn)行時(shí)檢查和解釋一個(gè)類實(shí)例的類型
  • 解構(gòu)器允許一個(gè)類實(shí)例釋放任何其所被分配的資源
  • 引用計(jì)數(shù)允許對(duì)一個(gè)類的多次引用

更多信息請(qǐng)參見繼承類型轉(zhuǎn)換,初始化,和自動(dòng)引用計(jì)數(shù)

注意: 結(jié)構(gòu)體總是通過被復(fù)制的方式在代碼中傳遞,因此請(qǐng)不要使用引用計(jì)數(shù)。

定義

類和結(jié)構(gòu)體有著類似的定義方式。我們通過關(guān)鍵字classstruct來分別表示類和結(jié)構(gòu)體,并在一對(duì)大括號(hào)中定義它們的具體內(nèi)容:

    class SomeClass {
        // class definition goes here
    }
    struct SomeStructure {
        // structure definition goes here
    }

注意: 在你每次定義一個(gè)新類或者結(jié)構(gòu)體的時(shí)候,實(shí)際上你是有效地定義了一個(gè)新的 Swift 類型。因此請(qǐng)使用 UpperCamelCase 這種方式來命名(如 SomeClassSomeStructure等),以便符合標(biāo)準(zhǔn)Swift 類型的大寫命名風(fēng)格(如String,IntBool)。相反的,請(qǐng)使用lowerCamelCase這種方式為屬性和方法命名(如framerateincrementCount),以便和類區(qū)分。

以下是定義結(jié)構(gòu)體和定義類的示例:

    struct Resolution {
        var width = 0
        var height = 0
    }
    class VideoMode {
        var resolution = Resolution()
        var interlaced = false
        var frameRate = 0.0
        var name: String?
    }

在上面的示例中我們定義了一個(gè)名為Resolution的結(jié)構(gòu)體,用來描述一個(gè)顯示器的像素分辨率。這個(gè)結(jié)構(gòu)體包含了兩個(gè)名為widthheight的存儲(chǔ)屬性。存儲(chǔ)屬性是捆綁和存儲(chǔ)在類或結(jié)構(gòu)體中的常量或變量。當(dāng)這兩個(gè)屬性被初始化為整數(shù)0的時(shí)候,它們會(huì)被推斷為Int類型。

在上面的示例中我們還定義了一個(gè)名為VideoMode的類,用來描述一個(gè)視頻顯示器的特定模式。這個(gè)類包含了四個(gè)儲(chǔ)存屬性變量。第一個(gè)是分辨率,它被初始化為一個(gè)新的Resolution結(jié)構(gòu)體的實(shí)例,具有Resolution的屬性類型。新VideoMode實(shí)例同時(shí)還會(huì)初始化其它三個(gè)屬性,它們分別是,初始值為false(意為“non-interlaced video”)的interlaced,回放幀率初始值為0.0frameRate和值為可選Stringnamename屬性會(huì)被自動(dòng)賦予一個(gè)默認(rèn)值nil,意為“沒有name值”,因?yàn)樗且粋€(gè)可選類型。

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

Resolution結(jié)構(gòu)體和VideoMode類的定義僅描述了什么是ResolutionVideoMode。它們并沒有描述一個(gè)特定的分辨率(resolution)或者視頻模式(video mode)。為了描述一個(gè)特定的分辨率或者視頻模式,我們需要生成一個(gè)它們的實(shí)例。

生成結(jié)構(gòu)體和類實(shí)例的語法非常相似:

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

結(jié)構(gòu)體和類都使用構(gòu)造器語法來生成新的實(shí)例。構(gòu)造器語法的最簡(jiǎn)單形式是在結(jié)構(gòu)體或者類的類型名稱后跟隨一個(gè)空括弧,如Resolution()VideoMode()。通過這種方式所創(chuàng)建的類或者結(jié)構(gòu)體實(shí)例,其屬性均會(huì)被初始化為默認(rèn)值。構(gòu)造過程章節(jié)會(huì)對(duì)類和結(jié)構(gòu)體的初始化進(jìn)行更詳細(xì)的討論。

屬性訪問

通過使用點(diǎn)語法dot syntax),你可以訪問實(shí)例中所含有的屬性。其語法規(guī)則是,實(shí)例名后面緊跟屬性名,兩者通過點(diǎn)號(hào)(.)連接:

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

在上面的例子中,someResolution.width引用someResolutionwidth屬性,返回width的初始值0。

你也可以訪問子屬性,如VideoModeResolution屬性的width屬性:

    println("The width of someVideoMode is \(someVideoMode.resolution.width)")
    // 輸出 "The width of someVideoMode is 0"

你也可以使用點(diǎn)語法為屬性變量賦值:

    someVideoMode.resolution.width = 1280
    println("The width of someVideoMode is now \(someVideoMode.resolution.width)")
    // 輸出 "The width of someVideoMode is now 1280"

注意: 與 Objective-C 語言不同的是,Swift 允許直接設(shè)置結(jié)構(gòu)體屬性的子屬性。上面的最后一個(gè)例子,就是直接設(shè)置了someVideoModeresolution屬性的width這個(gè)子屬性,以上操作并不需要重新設(shè)置resolution屬性。

結(jié)構(gòu)體類型的成員逐一構(gòu)造器(Memberwise Initializers for structure Types)

所有結(jié)構(gòu)體都有一個(gè)自動(dòng)生成的成員逐一構(gòu)造器,用于初始化新結(jié)構(gòu)體實(shí)例中成員的屬性。新實(shí)例中各個(gè)屬性的初始值可以通過屬性的名稱傳遞到成員逐一構(gòu)造器之中:

    let vga = Resolution(width:640, height: 480)

與結(jié)構(gòu)體不同,類實(shí)例沒有默認(rèn)的成員逐一構(gòu)造器。構(gòu)造過程章節(jié)會(huì)對(duì)構(gòu)造器進(jìn)行更詳細(xì)的討論。

結(jié)構(gòu)體和枚舉是值類型

值類型被賦予給一個(gè)變量,常數(shù)或者本身被傳遞給一個(gè)函數(shù)的時(shí)候,實(shí)際上操作的是其的拷貝。

在之前的章節(jié)中,我們已經(jīng)大量使用了值類型。實(shí)際上,在 Swift 中,所有的基本類型:整數(shù)(Integer)、浮點(diǎn)數(shù)(floating-point)、布爾值(Booleans)、字符串(string)、數(shù)組(array)和字典(dictionaries),都是值類型,并且都是以結(jié)構(gòu)體的形式在后臺(tái)所實(shí)現(xiàn)。

在 Swift 中,所有的結(jié)構(gòu)體和枚舉都是值類型。這意味著它們的實(shí)例,以及實(shí)例中所包含的任何值類型屬性,在代碼中傳遞的時(shí)候都會(huì)被復(fù)制。

請(qǐng)看下面這個(gè)示例,其使用了前一個(gè)示例中Resolution結(jié)構(gòu)體:

    let hd = Resolution(width: 1920, height: 1080)
    var cinema = hd

在以上示例中,聲明了一個(gè)名為hd的常量,其值為一個(gè)初始化為全高清視頻分辨率(1920 像素寬,1080 像素高)的Resolution實(shí)例。

然后示例中又聲明了一個(gè)名為cinema的變量,其值為之前聲明的hd。因?yàn)?code>Resolution是一個(gè)結(jié)構(gòu)體,所以cinema的值其實(shí)是hd的一個(gè)拷貝副本,而不是hd本身。盡管hdcinema有著相同的寬(width)和高(height)屬性,但是在后臺(tái)中,它們是兩個(gè)完全不同的實(shí)例。

下面,為了符合數(shù)碼影院放映的需求(2048 像素寬,1080 像素高),cinemawidth屬性需要作如下修改:

    cinema.width = 2048

這里,將會(huì)顯示cinemawidth屬性確已改為了2048

    println("cinema is now  \(cinema.width) pixels wide")
    // 輸出 "cinema is now 2048 pixels wide"

然而,初始的hd實(shí)例中width屬性還是1920

    println("hd is still \(hd.width ) pixels wide")
    // 輸出 "hd is still 1920 pixels wide"

在將hd賦予給cinema的時(shí)候,實(shí)際上是將hd中所存儲(chǔ)的值(values)進(jìn)行拷貝,然后將拷貝的數(shù)據(jù)存儲(chǔ)到新的cinema實(shí)例中。結(jié)果就是兩個(gè)完全獨(dú)立的實(shí)例碰巧包含有相同的數(shù)值。由于兩者相互獨(dú)立,因此將cinemawidth修改為2048并不會(huì)影響hd中的寬(width)。

枚舉也遵循相同的行為準(zhǔn)則:

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

上例中rememberedDirection被賦予了currentDirection的值(value),實(shí)際上它被賦予的是值(value)的一個(gè)拷貝。賦值過程結(jié)束后再修改currentDirection的值并不影響rememberedDirection所儲(chǔ)存的原始值(value)的拷貝。

類是引用類型

與值類型不同,引用類型在被賦予到一個(gè)變量、常量或者被傳遞到一個(gè)函數(shù)時(shí),操作的是引用,其并不是拷貝。因此,引用的是已存在的實(shí)例本身而不是其拷貝。

請(qǐng)看下面這個(gè)示例,其使用了之前定義的VideoMode類:

    let tenEighty = VideoMode()
    tenEighty.resolution = hd
    tenEighty.interlaced = true
    tenEighty.name = "1080i"
    tenEighty.frameRate = 25.0

以上示例中,聲明了一個(gè)名為tenEighty的常量,其引用了一個(gè)VideoMode類的新實(shí)例。在之前的示例中,這個(gè)視頻模式(video mode)被賦予了HD分辨率(1920*1080)的一個(gè)拷貝(hd)。同時(shí)設(shè)置為交錯(cuò)(interlaced),命名為“1080i”。最后,其幀率是25.0幀每秒。

然后,tenEighty 被賦予名為alsoTenEighty的新常量,同時(shí)對(duì)alsoTenEighty的幀率進(jìn)行修改:

    let alsoTenEighty = tenEighty
    alsoTenEighty.frameRate = 30.0

因?yàn)轭愂且妙愋?,所?code>tenEight和alsoTenEight實(shí)際上引用的是相同的VideoMode實(shí)例。換句話說,它們是同一個(gè)實(shí)例的兩種叫法。

下面,通過查看tenEightyframeRate屬性,我們會(huì)發(fā)現(xiàn)它正確的顯示了基本VideoMode實(shí)例的新幀率,其值為30.0

    println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
    // 輸出 "The frameRate property of theEighty is now 30.0"

需要注意的是tenEightyalsoTenEighty被聲明為常量((constants)而不是變量。然而你依然可以改變tenEighty.frameRatealsoTenEighty.frameRate,因?yàn)檫@兩個(gè)常量本身不會(huì)改變。它們并不存儲(chǔ)這個(gè)VideoMode實(shí)例,在后臺(tái)僅僅是對(duì)VideoMode實(shí)例的引用。所以,改變的是被引用的基礎(chǔ)VideoModeframeRate參數(shù),而不改變常量的值。

恒等運(yùn)算符

因?yàn)轭愂且妙愋停锌赡苡卸鄠€(gè)常量和變量在后臺(tái)同時(shí)引用某一個(gè)類實(shí)例。(對(duì)于結(jié)構(gòu)體和枚舉來說,這并不成立。因?yàn)樗鼈冏鳛橹殿愋?,在被賦予到常量、變量或者傳遞到函數(shù)時(shí),其值總是會(huì)被拷貝。)

如果能夠判定兩個(gè)常量或者變量是否引用同一個(gè)類實(shí)例將會(huì)很有幫助。為了達(dá)到這個(gè)目的,Swift 內(nèi)建了兩個(gè)恒等運(yùn)算符:

  • 等價(jià)于 ( === )
  • 不等價(jià)于 ( !== )

以下是運(yùn)用這兩個(gè)運(yùn)算符檢測(cè)兩個(gè)常量或者變量是否引用同一個(gè)實(shí)例:

    if tenEighty === alsoTenTighty {
        println("tenTighty and alsoTenEighty refer to the same Resolution instance.")
    }
    //輸出 "tenEighty and alsoTenEighty refer to the same Resolution instance."

請(qǐng)注意“等價(jià)于"(用三個(gè)等號(hào)表示,===) 與“等于"(用兩個(gè)等號(hào)表示,==)的不同:

  • “等價(jià)于”表示兩個(gè)類類型(class type)的常量或者變量引用同一個(gè)類實(shí)例。
  • “等于”表示兩個(gè)實(shí)例的值“相等”或“相同”,判定時(shí)要遵照類設(shè)計(jì)者定義定義的評(píng)判標(biāo)準(zhǔn),因此相比于“相等”,這是一種更加合適的叫法。

當(dāng)你在定義你的自定義類和結(jié)構(gòu)體的時(shí)候,你有義務(wù)來決定判定兩個(gè)實(shí)例“相等”的標(biāo)準(zhǔn)。在章節(jié)運(yùn)算符函數(shù)(Operator Functions)中將會(huì)詳細(xì)介紹實(shí)現(xiàn)自定義“等于”和“不等于”運(yùn)算符的流程。

指針

如果你有 C,C++ 或者 Objective-C 語言的經(jīng)驗(yàn),那么你也許會(huì)知道這些語言使用指針來引用內(nèi)存中的地址。一個(gè) Swift 常量或者變量引用一個(gè)引用類型的實(shí)例與 C 語言中的指針類似,不同的是并不直接指向內(nèi)存中的某個(gè)地址,而且也不要求你使用星號(hào)(*)來表明你在創(chuàng)建一個(gè)引用。Swift 中這些引用與其它的常量或變量的定義方式相同。

類和結(jié)構(gòu)體的選擇

在你的代碼中,你可以使用類和結(jié)構(gòu)體來定義你的自定義數(shù)據(jù)類型。

然而,結(jié)構(gòu)體實(shí)例總是通過值傳遞,類實(shí)例總是通過引用傳遞。這意味兩者適用不同的任務(wù)。當(dāng)你在考慮一個(gè)工程項(xiàng)目的數(shù)據(jù)構(gòu)造和功能的時(shí)候,你需要決定每個(gè)數(shù)據(jù)構(gòu)造是定義成類還是結(jié)構(gòu)體。

按照通用的準(zhǔn)則,當(dāng)符合一條或多條以下條件時(shí),請(qǐng)考慮構(gòu)建結(jié)構(gòu)體:

  • 結(jié)構(gòu)體的主要目的是用來封裝少量相關(guān)簡(jiǎn)單數(shù)據(jù)值。
  • 有理由預(yù)計(jì)一個(gè)結(jié)構(gòu)體實(shí)例在賦值或傳遞時(shí),封裝的數(shù)據(jù)將會(huì)被拷貝而不是被引用。
  • 任何在結(jié)構(gòu)體中儲(chǔ)存的值類型屬性,也將會(huì)被拷貝,而不是被引用。
  • 結(jié)構(gòu)體不需要去繼承另一個(gè)已存在類型的屬性或者行為。

合適的結(jié)構(gòu)體候選者包括:

  • 幾何形狀的大小,封裝一個(gè)width屬性和height屬性,兩者均為Double類型。
  • 一定范圍內(nèi)的路徑,封裝一個(gè)start屬性和length屬性,兩者均為Int類型。
  • 三維坐標(biāo)系內(nèi)一點(diǎn),封裝x,yz屬性,三者均為Double類型。

在所有其它案例中,定義一個(gè)類,生成一個(gè)它的實(shí)例,并通過引用來管理和傳遞。實(shí)際中,這意味著絕大部分的自定義數(shù)據(jù)構(gòu)造都應(yīng)該是類,而非結(jié)構(gòu)體。

集合(Collection)類型的賦值和拷貝行為

Swift 中字符串(String),數(shù)組(Array)字典(Dictionary)類型均以結(jié)構(gòu)體的形式實(shí)現(xiàn)。這意味著String,Array,Dictionary類型數(shù)據(jù)被賦值給新的常量(或變量),或者被傳入函數(shù)(或方法)中時(shí),它們的值會(huì)發(fā)生拷貝行為(值傳遞方式)。

Objective-C中字符串(NSString),數(shù)組(NSArray)字典(NSDictionary)類型均以類的形式實(shí)現(xiàn),這與Swfit中以值傳遞方式是不同的。NSString,NSArray,NSDictionary在發(fā)生賦值或者傳入函數(shù)(或方法)時(shí),不會(huì)發(fā)生值拷貝,而是傳遞已存在實(shí)例的引用。

注意: 以上是對(duì)于數(shù)組,字典,字符串和其它值的拷貝的描述。 在你的代碼中,拷貝好像是確實(shí)是在有拷貝行為的地方產(chǎn)生過。然而,在 Swift 的后臺(tái)中,只有確有必要,實(shí)際(actual)拷貝才會(huì)被執(zhí)行。Swift 管理所有的值拷貝以確保性能最優(yōu)化的性能,所以你也沒有必要去避免賦值以保證最優(yōu)性能。(實(shí)際賦值由系統(tǒng)管理優(yōu)化)

下一篇:訪問控制