雖然函數能夠簡化代碼,可是當一個程序中出現成百上千的函數和變量時,代碼仍是會顯得很混亂。爲此,人們又引入了新的類型——類。它是人們構建代碼所用的一種通用、靈活的構造方式。本章將主要詳細講解類的使用。swift
類是一種新的數據類型,相似於生活中犬類、貓類等等。而對象則是將這個抽象的類進行了具體化。例如,在犬類中,有哈士奇,金毛等等,這些就是犬類的具體化,即對象。本節將講解類的建立以及如何將類進行具體化(即實例化)爲對象。ide
在一個類中一般能夠包含如圖8.1所示的內容。函數
圖8.1 類的構成工具
其中,這些內容的功能以下:spa
q 屬性:它將值和特定的類關聯。.net
q 下標腳本:訪問對象、集合等的快捷方式。調試
q 方法:實現某一特定的功能,相似於函數。code
在Swift中類的建立要比在Objective-C中簡單的多。在Objecttive-C中,須要使用須要@interface 和@end 對類中的內容進行聲明,還須要使用@implementation和@end 對類聲明的內容進行實現。在Xcode 6.3以前,它們須要放置在不一樣的文件中。雖然在Xcode 6.4中,它們能夠放置在一個文件中,可是也至關的麻煩。Swift語言推出了本身建立類的方式,只使用一個class關鍵字,其通常的建立形式以下:orm
class 類名{server
//具體內容
}
注意:在類中能夠定義屬性和方法,這些內容會在後面作詳細的介紹。類名可使用「大駱駝拼寫法」方式來命名(如SomeClass),以便符合標準Swift 類型的大寫命名風格(如String,Int和Bool)。對於後面所講的對象、屬性以及方法等可使用「小駱駝拼寫法」來命名。
【示例8-1】如下建立一個名爲NewClass的類。代碼以下:
class NewClass{
}
該類名稱爲NewClass。因爲其中沒有屬性和方法,因此它只是一個空類。
實例化對象也能夠稱爲類的實例,其語法形式以下:
var/let 對象名=類名()
【示例8-2】如下會建立一個類名爲NewClass的類,而後再進行實例化。代碼以下:
import Foundation
class NewClass{
}
let newClass=NewClass ()
注意:在進行實例化時,類名後必定要加上()。不然程序就會錯誤,如如下的代碼:
var newClass = NewClass
因爲在實例化時缺乏了(),致使程序出現如下的錯誤信息:
Expected member name or constructor call after type name
以上所講的這些只是簡單的實例化對象。它使用了最簡單的構造器來生成一個對象。在後面的章節中咱們會爲開發者講解構造器的具體用法。
在Objective-C中,屬性是使用關鍵字@property關鍵字進行聲明的內容。在Swift中,屬性能夠將值跟特定的類、結構或枚舉關聯。屬性通常分爲存儲屬性、計算屬性和類型屬性。本節將講解對這些屬性作詳細的講解。
存儲屬性就是存儲特定類中的一個常量或者變量。根據數據是否可變,分爲常量存儲屬性和變量存儲屬性。
1.定義存儲屬性
常量存儲屬性使用let關鍵字定義(聲明定義在一塊兒進行,爲了方便稱爲定義),其語法形式以下:
let 常量存儲屬性名:數據類型=初始值
變量存儲屬性可使用var關鍵字定義,其語法形式以下:
var 變量存儲屬性名:數據類型=初始值
【示例8-3】如下代碼定義類NewClass1,其中包含兩個屬性value1和value2,代碼以下:
class NewClass1 {
let value1=20
var value2:Int=10
}
其中,value1使用let定義爲常量存儲屬性,value2使用var定義爲變量存儲屬性。在定義存儲屬性時,初始值是必不可少的,不然,就會出現錯誤。例如,如下的代碼:
class NewClass1 {
let value1=20
var value2:Int
}
在此代碼中,因爲value2後面未加初始值,致使程序出現如下的錯誤信息:
Class 'NewClass1' has no initializers
2.訪問存儲屬性
對於這些存儲屬性的訪問,須要使用「.」點運算符。其語法形式以下:
對象名.常量存儲屬性名/變量存儲屬性名
【示例8-4】如下定義了3個存儲屬性firstValue、secondValue、thirdValue,而後進行訪問。代碼以下:
import Foundation
class NewClass{
let firstValue:Int = 0
let secondValue=200
var thirdValue:String="Hello"
}
let newclass=NewClass()
//存儲屬性的訪問
print("firstValue=\(newclass.firstValue)")
print("secondValue=\(newclass.secondValue)")
print("thirdValue=\(newclass.thirdValue)")
運行結果以下所示:
firstValue=0
secondValue=200
thirdValue=Hello
注意:對存儲屬性進行訪問時,只能夠對在本身類中定義的存儲屬性進行訪問,不然就會出現錯誤,代碼以下:
import Foundation
class NewClass1 {
var class1Value=10
}
class NewClass2 {
var class2Value=10
}
let newclass1=NewClass1()
print(newclass1.class1Value)
print(newclass1.class2Value)
在此代碼中,因爲class2Value存儲屬性是在NewClass2類中定義的,而不是NewClass1中定義的,因此程序就會出現如下的錯誤信息:
'NewClass1' does not have a member named 'class2Value'
存儲屬性除了可使用「.」點運算符進行讀取外,還能夠對其進行修改。修存儲改屬性的通常語法形式以下:
對象名.存儲屬性=修改的內容
【示例8-5】如下代碼就將secondValue的屬性值"Hello"修改成了"Swift",代碼以下:
import Foundation
class NewClass{
var secondValue:String="Hello"
}
let newclass=NewClass()
print("修改前:secondValue=\(newclass.secondValue)")
newclass.secondValue="Swift" //修改存儲實現
print("修改後:secondValue=\(newclass.secondValue)")
運行結果以下所示:
修改前:secondValue=Hello
修改後:secondValue=Swift
注意:只有變量存儲屬性才能夠進行屬性修改,常量存儲屬性不能夠進行屬性修改。如如下的代碼:
import Foundation
class NewClass{
let firstValue:Int = 0
}
let newclass=NewClass()
print("修改前:firstValue=\(newclass.firstValue)")
newclass.firstValue=100 //試圖對屬性firstValue的值進行修改
print("修改後:\(newclass.firstValue)")
因爲在類中使用了let對存儲屬性進行了定義,其值是不能夠進行修改的,因此出現瞭如下的錯誤信息:
annot assign to 'let' property 'firstValue'
3.延遲存儲屬性
若是開發者只有在第一次調用存儲屬性時才能肯定初始值,這時須要使用延遲存儲屬性實現。它的定義通常須要使用關鍵字lazy實現的,其語法形式以下:
lazy var 屬性名:數據類型=初始內容
注意:在延遲存儲屬性中初始內容是不能夠省去的。數據類型也是能夠省去的,由於swift會根據初始內容自行判斷數據類型。
【示例8-6】如下將使用lazy來定義一個延遲存儲屬性importer,代碼以下:
import Foundation
class DataImporter {
var fileName = 123456
}
class DataManager {
lazy var importer = DataImporter()
var data = [String]()
}
let manager = DataManager()
manager.data += ["Some more data"]
print(manager.data)
print(manager.importer.fileName)
在沒有調用manager.importer.fileName時,實例的 importer屬性尚未被建立。運行結果以下所示:
[Some more data]
123456
咱們可使用斷點調試的方法對此代碼進行調試,來查看它的運行結果。具體步驟以下:
(1)爲幾行關鍵代碼添加斷點,並再添加一行代碼,來查看添加importer的值,如圖8.2所示。
圖8.2 添加斷點
(2)單擊運行按鈕,此時會在第一個斷點處出現一個藍色的箭頭,表示此行代碼在運行。而後選擇Debug|Continue命令,按下調試窗口工具欄中的Continue program execution按鈕,查看程序的執行,其中,可使用查看器來觀察屬性值的變化。屬性查看器位於調試信息窗口左半部分,如圖8.3所示。程序的執行,如圖8.4所示。其中,看到的self、data、importer.storage(由於importer是延遲屬性,爲了和其餘屬性區分,因此在查看器上看到是importer.storage)等都是屬性。它們會隨程序的執行爲改變。
圖8.3 查看器位置
圖8.4 調試
在此圖中程序執行到第3步,也就是第三個圖時,類DataManager的屬性data初始化,但沒有給importer.storage屬性進行初始化,一直爲nil,直到執行到第7步,即第7個圖時,才爲importer.storage屬性的屬性初始化。
在定義一個延遲存儲屬性時須要注意如下2點,
(1)定義一個延遲存儲屬性時除了lazy外,還須要使用var關鍵字,可是不能使用let關鍵字,不然程序就會出現錯誤,如如下代碼:
class DataImporter {
var fileName = 123456
}
class DataManager {
lazy let importer = DataImporter()
var data = [String]()
}
因爲在定義延遲屬性時使用了let關鍵字,因此致使程序出現瞭如下的錯誤:
'lazy' cannot be used on a let
(2)初始內容是不能夠省去的,不然程序就會出現錯誤,如如下的代碼,定義了一個沒有初始值的延遲屬性。代碼以下:
class DataManager {
lazy var value:Int
}
因爲在此代碼中沒有爲value指定初始值,致使程序出現瞭如下的錯誤:
lazy properties must have an initializer
除了存儲屬性外,類中還能夠定義計算屬性。計算屬性不存儲值,而是提供了一個getter和setter來分別進行獲取值和設置其餘屬性的值。getter使用get關鍵字進行定義,其通常形式以下:
get{
…
return 某一屬性值
}
setter使用set關鍵字進行定義,其通常語法形式以下:
set(參數名稱){
…
屬性值=某一個值
…
}
固然,它也能夠沒有參數名稱。這種狀況會後面的內容中講解。在計算屬性中同時包含了getter和setter,其通常定義形式以下:
var 屬性名:數據類型{
get{
…
return 某一屬性值
}
set(參數名稱){
…
屬性值=某一個值
…
}
}
【示例8-7】如下代碼定義了一個類WalletClass,用來保存錢包中的金額,其默認單位爲美圓。爲了方便用戶以人民幣爲單位進行訪問值和設置值,因此使用了計算屬性cal。代碼以下:
import Foundation
class WalletClass{
var money=0.0
var cal:Double{ //定義計算屬性cal
get{ //定義getter
let RMB=money*6.1
return RMB //返回以人民幣爲單位的金額
}
set(RMB){ //定義setter
money=RMB/6.1 //返回以美圓爲單位的金額
}
}
}
var mywallet=WalletClass()
mywallet.cal=(20)
//輸出
print(mywallet.cal)
print(mywallet.money)
運行結果以下所示:
20.0
3.27868852459016
注意:在使用計算屬性時須要注意如下三點:
1.定義計算屬性的關鍵字
在定義一個計算屬性時,必須且只能使用var關鍵字,不然就會出現錯誤。如下的代碼,將示例8-7的代碼作了一些修改,代碼以下:
class WalletClass{
var money=0.0
let cal:Double{
get{
var RMB=money*6.1
return RMB
}
set(RMB){
money=RMB/6.1
}
}
}
在此代碼中定義一個計算屬性,可是使用了let關鍵字,致使程序出現瞭如下的錯誤:
'let' declarations cannot be a computed property
2.數據類型
在定義計算屬性時,必定要爲屬性指定一個明確的數據類型,不然就會出現錯誤提示。例如如下的代碼,是將示例8-7中的代碼作了一些修改。代碼以下:
class WalletClass{
var money=0.0
var cal{ //沒有設置cal的數據類型
get{
var RMB=money*6.1
return RMB
}
set(RMB){
money=RMB/6.1
}
}
}
在此代碼中因爲沒有爲計算屬性指定一個明確的數據類型,致使程序出現瞭如下的錯誤信息:
Computed property must have an explicit type
Type annotation missing in pattern
3.set後面的參數類型
在使用計算屬性時,set後面的參數類型要和返回值的類型相同,不須要再指定類型。不然,程序就會出現錯誤。如如下的代碼,此代碼是將示例8-7中的代碼作了一下修改,代碼以下:
class WalletClass{
var money=0.0
var cal:Double{ //沒有設置cal的數據類型
get{
var RMB=money*6.1
return RMB
}
set(RMB:String){ //爲參數定義了數據類型
money=RMB/6.1
}
}
}
在此代碼中,對set後面的參數RMB指定了數據類型,致使程序出現瞭如下的錯誤:
Expected ')' after setter value name
Expected '{' to start setter definition
4.沒有定義參數名稱
若是計算屬性的setter沒有定義表示新值的參數名,則可使用默認名稱newValue。
【示例8-8】如下代碼就使用了newValue來實現了華氏溫度和攝氏溫度的轉換。代碼以下:
import Foundation
class DegreeClass{
var degree=0.0
var cal :Double{
get{
let centigradedegree=(degree-32)/1.8
return centigradedegree
}
set{
degree=1.8*newValue+32 //沒有定義參數名稱,可使用默認的
}
}
}
var degreeClass=DegreeClass()
degreeClass.cal=(10.0)
print(degreeClass.cal)
print(degreeClass.degree)
運行結果以下所示:
10.0
50.0
4.定義參數名後不能使用默認參數名
在set後面若是定義了參數名稱,就不能再使用Swift默認的參數名稱newValue。不然,就會致使程序出現錯誤。如如下的代碼,將示例8-8作了一些修改,代碼以下:
import Foundation
class DegreeClass{
var degree=0.0
var cal :Double{
get{
let centigradedegree=(degree-32)/1.8
return centigradedegree
}
set(aaa){ //定義參數名稱後,使用默認參數
degree=1.8*newValue+32
}
}
}
…
在此代碼中,set後面定義了參數名稱,可是又使用了默認的參數名稱,致使程序出現瞭如下的錯誤:
Use of unresolved identifier 'newValue'
5.setter和getter的省略
在計算屬性中,若是隻有一個getter,則稱爲只讀計算屬性。只讀計算屬性能夠返回一個值,但不能設置新的值。
【示例8-9】如下將經過getter來獲取名稱的字符串。代碼以下:
import Foundation
class PersonName{
var name:String=""
var returnName :String{
if (name.isEmpty) {
return "NULL"
}else{
return name
}
}
}
var personClass=PersonName()
print("沒有名字時\(personClass.returnName)")
personClass.name=("Tom")
print("有名字時\(personClass.returnName)")
在此代碼中,當剛建立實例PersonName後,就去訪問returnName。因爲name默認爲空,因此會返回字符串"NULL"。再對name賦值後,再一次訪問returnName。因爲name不爲空,因此會返回name的內容。運行結果以下所示:
沒有名字時NULL
有名字時Tom
注意:1.在只讀計算屬性中,能夠將get關鍵字和花括號去掉。2.在C#等其餘語言中能夠將屬性分爲只讀屬性(只有getter)、只寫屬性(只有setter)和可讀可寫屬性。可是在Swift中就不一樣了,只有只讀計算屬性和可讀可寫計算屬性兩個。沒有隻寫計算屬性,不然程序就會出現錯誤,如如下的代碼:
class PersonName{
var name:String=""
var setName :String{
set{
…
}
}
在此代碼中定義了一個只寫計算屬性,致使程序出現瞭如下的錯誤:
Variable with a setter must also have a getter
類型屬性就是不須要對類進行實例化就可使用的屬性。它須要使用關鍵字class進行定義,其定義形式以下:
class var 類型屬性名:數據類型{
…
返回一個值
}
例以下面代碼定義了一個類型屬性count,代碼以下:
class var count:Int{
return 20
}
類型屬性也是能夠被訪問的,其訪問類型屬性的通常形式以下:
類名.類型屬性
【示例8-10】如下代碼定義了一個類型屬性newvalue,而後進行遍歷訪問該屬性的每個字符,並輸出。代碼以下:
import Foundation
class NewClass {
class var newvalue:String{ //定義類型屬性newvalue
return "Hello"
}
}
print(NewClass.newvalue)
print("遍歷NewClass.newvalue:")
//遍歷類型屬性newvalue的值
for index in NewClass.newvalue.characters {
print(index)
}
運行結果以下所示:
Hello
遍歷NewClass.newvalue:
H
e
l
l
o
在使用類型屬性時須要注意如下2點:
1.let關鍵字不能聲明類型屬性
定義類型屬性時除了有關鍵字class外,還須要使用var關鍵字,但不能使用let關鍵字,不然程序提示錯誤,如如下代碼,此代碼定義了一個類型屬性newvalue。代碼以下:
import Foundation
class NewClass {
class let newvalue:Int{
return 20
}
}
print(NewClass.newvalue)
在此代碼中使用了關鍵字let進行了類型屬性的聲明,致使程序出現瞭如下的錯誤:
'let' declarations cannot be computed properties
2.存儲屬性
在類型方法中不能使用存儲屬性,不然程序就會出現錯誤,如如下的代碼,此代碼實現的是輸出字符串"Hello"。
import Foundation
class NewClass {
var count:Int=20
class var newvalue:Int{
return count
}
}
print(NewClass.newvalue)
其中,count是存儲屬性,newvalue是類型屬性。在代碼中,將str用在newvalue中,致使程序出現瞭如下的錯誤:
'NewClass.Type' does not have a member named 'count'
3.對象不能訪問類型屬性
類型屬性只可使用類去訪問,而不可使用對象進行訪問。不然,就會出現錯誤,如如下的代碼:
import Foundation
class NewClass {
class var newvalue:Int{
return 20
}
}
var newClass=NewClass()
print(newClass.newvalue)
在此代碼中,定義了一個類型屬性newvalue,但在訪問它時使用了對象,致使程序出現瞭如下錯誤:
'NewClass' does not have a member named 'newvalue'
類型屬性和存儲屬性同樣,除了能夠進行訪問外,還能夠進行修改,其語法形式以下:
類名.類型屬性=修改的內容
【示例8-11】如下程序將類型屬性0變爲200,並輸出。代碼以下所示:
import Foundation
var value:Int=0
class NewClass{
class var count :Int{
get{
let newvalue=value
return newvalue
}
set{
value=newValue
}
}
}
print("修改前:\(NewClass.count)")
NewClass.count=200
print("修改後:\(NewClass.count)")
運行結果以下所示:
修改前:0
修改後:200
屬性監視器用來監控和響應屬性值的變化。每次屬性被設置值的時候,都會調用屬性監視器,哪怕是新的值和原先的值相同。一個屬性監視器由willSet和didSet組成,其定義形式以下:
var 屬性名:數據類型=初始值{
willSet(參數名){
…
}
didSet(參數名){
…
}
}
其中,willSet在設置新的值以前被調用,它會將新的屬性值做爲固定參數傳入。didSet在新的值被設置以後被調用,會將舊的屬性值做爲參數傳入,能夠爲該參數命名或者使用默認參數名oldValue。
【示例8-12】如下將使用屬性監視器監視totalSteps屬性值的變化。代碼以下:
import Foundation
class StepCounter {
var totalSteps: Int = 0 {
//完整的屬性監視器
willSet(newTotalSteps) {
print("新的值爲 \(newTotalSteps)")
}
didSet(old) {
if totalSteps > old {
print("與原來相比增減了 \(totalSteps - old) 個值")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 0
stepCounter.totalSteps = 200
stepCounter.totalSteps = 400
stepCounter.totalSteps = 800
運行結果以下所示:
新的值爲 0
新的值爲 200
與原來相比增減了 200 個值
新的值爲 400
與原來相比增減了 200 個值
新的值爲 800
與原來相比增減了 400 個值
注意:在使用屬性監視器時,須要使用注意如下4點:
1.不指定參數名
在willSet後面是能夠不指定參數的,這時Swift會使用默認newValue表示新值。例如如下的代碼在沒有指定willSet參數的狀況下,直接使用newValue來輸出新的值。代碼以下:
import Foundation
class StepCounter {
var totalSteps: Int=0 {
willSet {
print("新的值爲 \(newValue)")
}
didSet (old){
if totalSteps > old {
print("與原來相比增減了 \(totalSteps - old) 個值")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 0
stepCounter.totalSteps = 200
運行結果以下所示:
新的值爲 0
新的值爲 200
與原來相比增減了 200 個值
一樣在didSet後面也能夠不指定參數名,此時Swift會使用默認參數名oldValue。如如下的代碼,此是示例8-12的代碼作了一個修改,代碼以下:
import Foundation
class StepCounter {
var totalSteps: Int = 0 {
//完整的屬性監視器
willSet(newTotalSteps) {
print("新的值爲 \(newTotalSteps)")
}
didSet {
if totalSteps > oldValue {
print("與原來相比增減了 \(totalSteps - oldValue) 個值")
}
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 0
…
2.默認參數不能夠交換使用
在使用willSet和didSet時,它們默認的參數能夠是不能夠交換使用的。例如在willSet中使用的newValue不可使用在didSet中,在didSet中使用的oldValue不可使用在willSet中,不然程序就會出現錯誤。例如如下的代碼,將示例8-12作了一些修改,代碼以下:
import Foundation
class StepCounter {
var totalSteps: Int = 0 {
//完整的屬性監視器
willSet {
print("新的值爲 \(newValue)")
}
didSet {
if newValue > oldValue {
print("與原來相比增減了 \(newValue - oldValue) 個值") //輸出新值和舊值之間的差值
}
}
}
}
let stepCounter = StepCounter()
…
在此代碼中,因爲在didSet中使用了willSet中的默認參數,致使程序出現瞭如下的錯誤:
Use of unresolved identifier 'newValue'
3.延遲屬性不能使用屬性監視器
在延遲屬性中不可使用屬性監視器,不然程序會出現錯誤。如如下的代碼:
class StepCounter {
lazy var totalSteps: Int=0 {
willSet {
print("新的值爲 \(newValue)")
}
didSet {
if totalSteps > oldValue {
print("與原來相比增減了 \(totalSteps - oldValue) 個值")
}
}
}
}
此代碼中延遲屬性中添加了屬性監視器,致使程序出現了以下的錯誤:
lazy properties may not have observers
4.分開使用willSet和didSet
一個完整的屬性監視器由willSet和didSet組成,可是willSet和didSet也能夠單獨使用。例如如下的代碼就只使用了willSet輸出了新值的信息。代碼以下:
import Foundation
class StepCounter {
var totalSteps: Int=0 {
willSet {
print("新的值爲 \(newValue)")
}
}
}
let stepCounter = StepCounter()
stepCounter.totalSteps = 0
stepCounter.totalSteps = 200
stepCounter.totalSteps = 600
stepCounter.totalSteps = 1200
這裏屬性監視器total只使用了willset,而沒有使用didset。運做結果以下所示:
新的值爲 0
新的值爲 200
新的值爲 600
新的值爲 1200
本文選自:Swift2.0語言快速入門v3.0 大學霸內部資料,轉載請註明出處,尊重技術尊重IT人!