Swift教程之類與構造詳解。本站提示廣大學習愛好者:(Swift教程之類與構造詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是Swift教程之類與構造詳解正文
類與構造是編程人員在代碼中會常常用到的代碼塊。在類與構造中可以像界說常量,變量和函數一樣,界說相干的屬性和辦法以此來完成各類功效。
和其它的編程說話不太雷同的是,Swift不須要零丁創立接口或許完成文件來應用類或許構造。Swift中的類或許構造可以在單文件中直接界說,一旦界說完成後,就可以夠被直接其它代碼應用。
留意:一個類的實例普通被視作一個對象,然則在Swift中,類與構造更像是一個函數辦法,在後續的章節中更多地是講述類和構造的功效性。
1、類和構造的異同
類和構造有一些類似的處所,它們都可以:
界說一些可以賦值的屬性;
界說具有功效性的辦法
界說下標,應用下口號法
界說初始化辦法來設置初始狀況
在原完成辦法上的可擴大性
依據協定供給某一特定種別的根本功效
更多內容可以浏覽:屬性,辦法,下標,初始化,擴大和協定等章節
類還有一些構造不具有的特征:
類的繼續性
對類實例及時的類型轉換
析構一個類的實例使之釋放空間
援用計數,一個類實例可以有多個援用
更多內容可以浏覽:繼續,類型轉換,初始化主動援用計數
留意:構造每次在代碼中傳遞時都是復制了一全部,所以不要應用援用計數
界說語法
類和構造具有類似的界說語法,應用class症結詞界說一個類,struct症結詞界說構造。每一個界說都由一對年夜括號包括:
class SomeClass {
// class definition goes here
}
struct SomeStructure {
// structure definition goes here
}
留意:在界說類和構造時,普通應用UpperCamelCase定名法來界說類和構造的稱號,好比SomeClass和SomeStructure,如許也相符Swift其它類型的尺度。而給屬性和辦法定名時,普通時刻lowerCamelCase定名法,好比frameRate和incrementCount等。
上面是一個構造和一個類的界說示例:
struct Resolution {
var width = 0
var height = 0
}
class VideoMode {
var resolution = Resolution()
var interlaced = falsevar
frameRate = 0.0
var name: String?
}
下面的例子起首界說了一個叫Resolution的構造,用來描寫一個像素顯示的分辯率,它有兩個屬性分離叫width和height。這兩個屬性被默許界說為Int類型,初始化為0.
以後界說了一個叫VideoMode的類,為視頻顯示的顯示方法。這個類有四個屬性,第一個屬性resolution自己又是一個構造,然後是別的兩個屬性。最初一個屬性用到了可選字符串類型String?,表現這個屬性可以存在,或許不存在為nil。
類和構造的實例
下面的兩個界說僅僅是界說了卻構Resolution和類VideoMode的全體款式,它們自己不是一個特定的分辯率或許顯示方法,這時候候就須要實例化這個構造和類。
實例化的語法類似:
let someResolution = Resolution()
let someVideoMode = VideoMode()
類和構造都應用實例語法來完成實例化。最簡略的實例語法就是用兩個括號()完成。在這類情形下界說的實例中的屬性都邑完成默許初始化。更多內容可以參考初始化一章。
拜訪屬性
應用.語法便可以便利地拜訪一個實例的屬性。在.語法中,在實例名以後加上(.)再加上屬性名便可,不須要空格:
println("The width of someResolution is \(someResolution.width)")
// prints "The width of someResolution is 0"
在這個例子中,someResolution.width表現someResolution的width屬性,前往了它的初始值0
也能夠應用.語法持續地獲得屬性的屬性,好比VideoMode中resolution屬性的width屬性
println("The width of someVideoMode is \(someVideoMode.resolution.width)")
// prints "The width of someVideoMode is 0"
應用這類辦法不只可以拜訪,也能夠賦值:
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可以或許直接設置一個構造屬性的子屬性,就像下面這個例子一樣。
構造類型的成員初始化辦法
每一個構造都有一個成員初始化辦法,可以在初始化的時刻經由過程應用屬性稱號來指定每個屬性的初始值:
let vga = Resolution(width: 640, height: 480)
然則和構造分歧,類實例不克不及夠應用成員初始化辦法,在初始化一章有專門的引見。
2、構造和列舉類型是數值類型
數值類型是說當它被賦值給一個常量或許變量,或許作為參數傳遞給函數時,是完全地復制了一個新的數值,而不是僅僅轉變了援用對象。
現實上讀到這裡你曾經在後面幾章見過數值類型了,一切Swift中的基本類型-整型,浮點型,布爾類型,字符串,數組和字典都是數值類型。它們也都是由構造來完成的。
在Swift中一切的構造和列舉類型都是數值類型。這意味這你實例化的每一個構造和列舉,其包括的一切屬性,都邑在代碼中傳遞的時刻被完全復制。
上面的這個例子可以解釋這個特征:
let hd = Resolution(width: 1920, height: 1080)
var cinema = hd
聲清楚明了一個常量hd,是Resolution的實例化,寬度是1920,高度是1080,然後聲清楚明了一個變量cinema,和hd雷同。這個時刻注解,cinema和hd是兩個實例,固然他們的寬度都是1920,高度都是1080。
假如把cinema的寬度更改成2048,hd的寬度不會變更,仍然是1920
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"
這注解當hd被賦值給cinema時,是完全地復制了一個全新的Resolution構造給cinema,所以當cinema的屬性被修正時,hd的屬性不會變更。
上面的例子演示的是列舉類型:
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"
雖然經由幾回賦值,rememberedDirection仍然沒有變更,這是由於在每次賦值進程中,都是將數值類型完全地復制了過去。
3、類是援用類型
和數值類型分歧援用類型不會復制全部實例,當它被賦值給別的一個常量或許變量的時刻,而是會樹立一個和已有的實例相干的援用來表現它。
上面是援用的示例,VideoMode被界說為一個類:
let tenEighty = VideoMode()
tenEighty.resolution = hd
tenEighty.interlaced = true
tenEighty.name = "1080i"
tenEighty.frameRate = 25.0
分離將這個實例tenEighty的四個屬性初始化,然後tenEighty被賦值給了別的一個叫alsoTenEighty的常量,然後alsoTenEighty的frameRate被修正了
let alsoTenEighty = tenEighty
alsoTenEighty.frameRate = 30.0
因為類是一個援用類型,所以tenEighty和alsoTenEighty現實上是統一個實例,僅僅只是應用了分歧的稱號罷了,我們經由過程檢討frameRate可以證實這個成績:
println("The frameRate property of tenEighty is now \(tenEighty.frameRate)")
// prints "The frameRate property of tenEighty is now 30.0"
留意到tenEighty和alsoTenEighty是被界說為常量的,而不是變量。然則我們照樣可以轉變他們的屬性值,這是由於它們自己現實上沒有轉變,它們並沒有保留這個VideoMode的實例,僅僅只是援用了一個VideoMode實例,而我們修正的也是它們援用的實例中的屬性。
特點操作
由於類是援用類型,那末便可能存在多個常量或許變量只想統一個類的實例(這關於數值類型的構造和列舉是不成立的)。
可以經由過程以下兩個操作來斷定兩個常量或許變量能否援用的是統一個類的實例:
雷同的實例(===)
分歧的實例(!==)
應用這些操作可以檢討:
if tenEighty === alsoTenEighty {
println("tenEighty and alsoTenEighty refer to the same Resolution instance.")
}
// prints "tenEighty and alsoTenEighty refer to the same Resolution instance."
留意是雷同的實例斷定應用三個持續的等號,這和相等(兩個等號)是分歧的
實例雷同表現的是兩個變量或許常量所援用的是統一個類的實例
相等是指兩個實例在數值上的相等,或許雷同。
當你界說一個類的時刻,就須要解釋甚麼樣的時刻是兩個類相等,甚麼時刻是兩個類不相等。更多內容可以從相等操作一章中取得。
指針
假如你有C,C++或許Objective-C的編程經歷,你必定曉得在這些說話中應用指針來援用一個內存地址。Swift中援用一個實例的常量或變量跟C中的指針相似,然則不是一個直接指向內存地址的指針,也不須要應用*記號表現你正在界說一個援用。Swift中援用和其它變量,常量的界說辦法雷同。
4、若何選擇應用類照樣構造
在代碼中可以選擇類或許構造來完成你所須要的代碼塊,完成響應的功效。然則構造實例傳遞的是值,而類實例傳遞的是援用。那末關於分歧的義務,應當斟酌到數據構造和功效的需求分歧,從而選擇分歧的實例。
普通來講,上面的一個或多個前提知足時,應該選擇創立一個構造:
構造重要是用來封裝一些簡略的數據值
當賦值或許傳遞的時刻更願望這些封裝的數據被賦值,而不是被援用曩昔
一切被構造存儲的屬性自己也是數值類型
構造不須要被別的一個類型繼續或許完成其它行動
一些比擬好的應用構造的例子:
一個幾何外形的尺寸,能夠包含寬度,高度或許其它屬性,每一個屬性都是Double類型的
一個序列的對應關系,能夠包含開端start和長度length屬性,每一個屬性都是Int類型的
3D坐標系中的一個點,包含x,y和z坐標,都是Double類型
在其它情形下,類會是更好的選擇。也就是說普通情形下,自界說的一些數據構造普通都邑被界說為類。
5、聚集類型的賦值和復制操作
Swift中,數組Array和字典Dictionary是用構造來完成的,然則數組與字典和其它構造在停止賦值或許作為參數傳遞給函數的時刻有一些分歧。
而且數組和字典的這些操作,又與Foundation中的NSArray和NSDictionary分歧,它們是用類來完成的。
留意:上面的末節將會引見數組,字典,字符串等的復制操作。這些復制操作看起來都曾經產生,然則Swift只會在確切須要復制的時刻才會完全復制,從而到達最優的機能。
字典的賦值和復制操作
每次將一個字典Dictionary類型賦值給一個常量或許變量,或許作為參數傳遞給函數時,字典會在賦值或許函數挪用時才會被復制。這個進程在下面的末節:構造和列舉是數值類型中描寫了。
假如字典中的鍵值是數值類型(構造或許列舉),它們在賦值的時刻會同時被復制。相反,假如是援用類型(類或許函數),援用自己將會被復制,而不是類實例或許函數自己。字典的這類復制方法和構造雷同。
上面的例子演示的是一個叫ages的字典,存儲了一些人名和年紀的對應關系,當賦值給copiedAges的時刻,外面的數值同時被完全復制。當轉變復制了的數值的時刻,原本的數值不會變更,以下例子:
var ages = ["Peter": 23, "Wei": 35, "Anish": 65, "Katya": 19]
var copiedAges = ages
這個字典的鍵是字符串String類型,值是Int類型,都是數值類型,那末在賦值的時刻都邑被完全復制。
copiedAges["Peter"] = 24
println(ages["Peter"])
// prints "23"
數組的賦值和復制操作
和字典Dictionary類型比起來,數組Array的賦值和復制操作就加倍龐雜。Array類型和C說話中的相似,僅僅只會在須要的時刻才會完全復制數組的值。
假如將一個數組賦值給一個常量或許變量,或許作為一個參數傳遞給函數,復制在賦值和函數挪用的時刻其實不會產生。這兩個數組將會同享一個元素序列,假如你修正了個中一個,別的一個也將會轉變。
關於數組來講,復制只會在你停止了一個能夠會修正數組長度操作時才會產生。包含拼接,添加或許移除元素等等。當復制現實產生的時刻,才會像字典的賦值和復制操作一樣。
上面的例子演示了數組的賦值操作:
var a = [1, 2, 3]
var b = a
var c = a
數組a被賦值給了b和c,然後輸入雷同的下標會發明:
println(a[0])
// 1
println(b[0])
// 1
println(c[0])
// 1
假如轉變a中的某個值,會發明b和c中的數值也會隨著轉變,由於賦值操作沒有轉變數組的長度:
a[0] = 42
println(a[0])
// 42
println(b[0])
// 42
println(c[0])
// 42
然則,假如在a中添加一個新的元素,那末就轉變了數組的長度,這個時刻就會產生現實的復制操作。假如再轉變a中元素的值,b和c中的元素將不會產生轉變:
a.append(4)
a[0] = 777
println(a[0])
// 777
println(b[0])
// 42
println(c[0])
// 42
設置數組是獨一的
假如可以在對數組停止修正前,將它設置為獨一的就最好了。我們可以經由過程應用unshare辦法來將數組自行拷貝出來,成為一個獨一的實體。
假如多個變量援用了統一個數組,可使用unshare辦法來完成一次“自力”
b.unshare()
這時候候假如再修正b的值,c的值也不會再受影響
b[0] = -105
println(a[0])
// 777
println(b[0])
// -105
println(c[0])
// 42
檢討兩個數組時刻共用了雷同的元素
應用實例相等操作符來斷定兩個數組能否共用了元素(===和!===)
上面這個例子演示的就是斷定能否共用元素:
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."
也能夠應用這個操作來斷定兩個子數組能否有共用的元素:
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."
強迫數組拷貝
經由過程挪用數組的copy辦法來完成強迫拷貝。這個辦法將會完全復制一個數組到新的數組中。
上面的例子中這個叫names的數組會被完全拷貝到copiedNames中去。
var names = ["Mohsen", "Hilary", "Justyn", "Amy", "Rich", "Graham", "Vic"]
var copiedNames = names.copy()
經由過程轉變copiedNames的值可以驗證,數組曾經被完全拷貝,不會影響到之前的數組:
copiedNames[0] = "Mo"
println(names[0])
// prints "Mohsen"
留意:假如你不肯定你須要的數組能否是自力的,那末僅僅應用unshare便可以了。而copy辦法不論以後是否是自力的,都邑完全拷貝一次,哪怕這個數組曾經是unshare的了。