一溉潭、類
Swift類是構(gòu)建代碼所用的一種通用且靈活的構(gòu)造體。
我們可以為類定義屬性(常量少欺、變量)和方法喳瓣。
與其他編程語言所不同的是,Swift并不要求你為自定義類去創(chuàng)建獨(dú)立的接口和實(shí)現(xiàn)文件赞别。你所要做的是在一個(gè)單一文件中定義一個(gè)類畏陕,系統(tǒng)會(huì)自動(dòng)生成面向其他代碼的外部接口。
類和結(jié)構(gòu)體對比
Swift中類和結(jié)構(gòu)體有很多共同點(diǎn)仿滔。共同處在于:
1.定義屬性用于存儲(chǔ)值惠毁。
2.定義方法用于提供功能犹芹。
3.定義附屬腳本用于訪問值。
4.定義構(gòu)造器用于生成初始化值鞠绰。
5.通過擴(kuò)展以增加默認(rèn)實(shí)現(xiàn)的功能腰埂。
6.符合協(xié)議以對某類提供能標(biāo)準(zhǔn)功能。
與結(jié)構(gòu)體相比蜈膨,類還有如下的附加功能:
1.繼承允許一個(gè)類繼承另一個(gè)類的特征屿笼。
2.類型轉(zhuǎn)換允許在運(yùn)行時(shí)檢查和解釋一個(gè)類實(shí)例的類型。
3.解構(gòu)器允許一個(gè)類實(shí)例釋放任何其所被分配的資源翁巍。
4.引用計(jì)數(shù)器允許對一個(gè)類的多次引用驴一。
語法:
class className {
Definition 1
Definition 2
......
Definition N
}
類定義
class student {
var studentName : String
var mark1 : Int
var mark2 : Int
}
實(shí)例化類:
let studentRecord = student()
實(shí)例:
class MarksStruct {
var mark : Int
init(mark : Int) {
self.mark = mark
}
}
class studentMarks {
var mark = 300
}
let marks = studentMarks()
print("成績?yōu)閈(marks.mark)")
以上程序的執(zhí)行結(jié)果為:
成績?yōu)?300
作為引用類型訪問類屬性
類屬性可以通過,來訪問灶壶。格式為:實(shí)例化類名.屬性名:
class MarksStruct {
var mark : Int
init(mark : Int) {
self.mark = mark
}
}
class studentMarks {
var mark1 = 300
var mark2 = 400
var mark3 = 900
}
let marks = studentMarks()
print("Mark is \(marks.mark1)")
print("Mark is \(marks.mark2)")
print("Mark is \(marks.mark3)")
以上程序執(zhí)行輸出結(jié)果:
Mark1 is 300
Mark2 is 400
Mark3 is 900
恒等運(yùn)算符
因?yàn)轭愂且妙愋突着浚锌赡苡卸鄠€(gè)常量和變量在后臺(tái)同時(shí)引用某一個(gè)實(shí)例。
為了能夠判斷兩個(gè)常量或者變量是否引用同一個(gè)類實(shí)例例朱,Swift內(nèi)建了兩個(gè)恒等運(yùn)算符孝情。
實(shí)例
class SampleClass : EquaTable {
let myProperty : String
init(s : Sting) {
myProperty = s
}
}
func == (lhs: SampleClass, rhs: SampleClass) -> Bool {
return lhs.myProperty == rhs.myProperty
}
let spClass1 = SampleClass(s : "Hello")
let spClass2 = SampleClass(s : "Hello")
if spClass1 === spClass2 {
print("引用相同的類實(shí)例\(spClass1)")
}
if spClass1 !== spClass2 {
print("引用不相同的類實(shí)例\(spClass2)")
}
以上程序執(zhí)行輸出結(jié)果為:
引用不相同的類實(shí)例:SampleClass
二、屬性
Swift屬性將值與特定的類洒嗤、結(jié)構(gòu)或枚舉關(guān)聯(lián)箫荡。
屬性可分為存儲(chǔ)屬性和計(jì)算屬性:
存儲(chǔ)屬性和計(jì)算屬性通常用于特定類型的實(shí)例。
屬性也可以直接用于類型本身渔隶,這種屬性稱為類型屬性羔挡。
另外,還可以定義屬性觀察器來監(jiān)控屬性值的變化间唉,以此來觸發(fā)一個(gè)自定義的操作绞灼。屬性觀察器來監(jiān)控屬性值的變化,以此來觸發(fā)一個(gè)自定義的操作呈野。屬性觀察器可以添加到自己寫的存儲(chǔ)屬性上低矮,也可以添加到從父類繼承的屬性上。
存儲(chǔ)屬性
簡單來說被冒,一個(gè)存儲(chǔ)屬性就是存儲(chǔ)在特定類或結(jié)構(gòu)體的實(shí)例里的一個(gè)常量或變量军掂。
存儲(chǔ)屬性可以是變量存儲(chǔ)屬性(用關(guān)鍵字var定義),也可以是常量存儲(chǔ)屬性(用關(guān)鍵字let定義)昨悼。
1.可以在定義存儲(chǔ)屬性的時(shí)候指定默認(rèn)值蝗锥。
2.也可以在構(gòu)造過程中設(shè)置或修改存儲(chǔ)屬性的值,甚至修改常量存儲(chǔ)屬性的值率触。
struct Number {
var digits : Int
let pi = 3.1415
}
var n = Number(digits: 12345)
n.digits = 67
print("\(n.digits)")
print("\(n.pi)")
以上程序執(zhí)行輸出結(jié)構(gòu)為:
67
3.1415
考慮一下代碼:
let pi = 3.1415
代碼中pi定義存儲(chǔ)屬性的時(shí)候指定默認(rèn)值(pi = 3.1415)终议,所以不管你什么時(shí)候?qū)嵗Y(jié)構(gòu)體,它都不會(huì)改變。如果你定義的是一個(gè)常量存儲(chǔ)屬性穴张,如果嘗試修改它就會(huì)報(bào)錯(cuò)细燎,如下所示:
struct Number {
var digits : Int
let numbers = 3.1415
}
var n = Number(digits: 12345)
n.digits = 67
print("\(n.digits)")
print("\(n.numbers)")
n.numbers = 8.7
以上程序執(zhí)行將會(huì)報(bào)錯(cuò),錯(cuò)誤如下所示:
error: cannot assign to property: 'numbers' is a 'let' constant
n.numbers = 8.7
意思為‘numbers’是一個(gè)常量陆馁,你不能修改它。
延遲存儲(chǔ)屬性
延遲存儲(chǔ)屬性是指當(dāng)?shù)谝淮伪徽{(diào)用的時(shí)候才會(huì)計(jì)算其初始值的屬性合愈。
在屬性聲明前使用lazy來標(biāo)示一個(gè)延遲存儲(chǔ)屬性叮贩。
注意:
必須將延遲存儲(chǔ)屬性聲明成變量(使用var關(guān)鍵字),因?yàn)閷傩缘闹翟趯?shí)例構(gòu)造完成之前可能無法得到佛析。而常量屬性在構(gòu)造過程完成之前必須要有初始值益老,因此無法聲明成延遲屬性。
延遲存儲(chǔ)屬性一般用于:
1.延遲對象的創(chuàng)建寸莫。
2.當(dāng)屬性的值依賴于其他未知類
class sample {
lazy var no = number()
}
class number {
var name = "Apple"
}
var firstSample = sample()
print(firstSample.no.name)
以上程序執(zhí)行輸出結(jié)果為:
Apple
實(shí)例化變量
如果您有過OC經(jīng)驗(yàn)捺萌,應(yīng)該知道OC為類實(shí)例存儲(chǔ)值和引用提供兩種方法。對于屬性來說膘茎,也可以使用實(shí)例變量作為屬性值的后端存儲(chǔ)桃纯。
Swift編程語言中把這些理論統(tǒng)一用屬性來實(shí)現(xiàn)。Swift中的屬性沒有對應(yīng)的實(shí)例變量披坏,屬性的后端存儲(chǔ)也無法直接訪問态坦。這就避免了不同場景下訪問方式的困擾,同時(shí)也將屬性的定義簡化成一個(gè)語句棒拂。
一個(gè)類型中屬性的全部信息一一包括命名伞梯、類型和內(nèi)存管理特征--都在唯一一個(gè)地方(類型定義中)定義。
計(jì)算屬性
除存儲(chǔ)屬性外帚屉,類谜诫、結(jié)構(gòu)體和枚舉可以定義計(jì)算屬性,計(jì)算屬性不直接存儲(chǔ)值攻旦,而是提供一個(gè)getter來獲取值喻旷,一個(gè)可選的setter來間接設(shè)置其他屬性或變量。
class sample {
var nol = 0.0, no2 = 0.0
var length = 300.0, breadth = 150.0
var middle: (Double, Double) {
get {
return (length / 2, breadth / 2)
}
set(axis) {
no1 = axis.0 - (length / 2)
no2 = axis.1 - (length / 2)
}
}
}
var result = sample()
print(result.middle)
result.middle = (0.0, 10.0)
print(result.no1)
print(result.no2)
以上程序執(zhí)行輸出結(jié)果為:
(150.0牢屋,75.0)
-150.0
-65.0
如果計(jì)算屬性的setter沒有定義表示新值參數(shù)名掰邢,則可以使用默認(rèn)名稱newValue。
只讀計(jì)算屬性
只有g(shù)etter沒有setter的計(jì)算屬性就是只讀計(jì)算屬性伟阔。
只讀計(jì)算屬性總是返回一個(gè)值辣之,可以通過點(diǎn)(.)運(yùn)算符訪問,單但不能設(shè)置新的值皱炉。
class film {
var head = ""
var duration = 0.0
var metaInfo: [String : String] {
return [
"head" : self.head,
"duration" : "\(self,duration)"
]
}
}
var movie = film()
movie.head = "Swift屬性"
movie.duration = 3.09
print(movie.metaInfo["head"]!)
print(movie.metaInfo["duration"]!)
以上程序執(zhí)行輸出結(jié)果為:
Swift屬性
3.09
注意:
必須使用var關(guān)鍵字定義計(jì)算屬性怀估,包括只讀計(jì)算屬性,因?yàn)樗鼈兊闹挡皇枪潭ǖ摹et關(guān)鍵字只用來聲明常量屬性多搀,表示初始化后再也無法修改的值歧蕉。
屬性觀察器
屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器康铭,甚至新的值和現(xiàn)在的值相同的時(shí)候也不例外惯退。
可以為除了延遲存儲(chǔ)屬性之外的其他存儲(chǔ)屬性添加屬性觀察器,也可以通過重載屬性的方式為繼承的屬性(包括存儲(chǔ)屬性和計(jì)算屬性)添加屬性觀察器从藤。
注意:
不需要為無法重載的計(jì)算屬性添加屬性觀察器催跪,因?yàn)榭梢酝ㄟ^setter直接監(jiān)控和響應(yīng)值的變化。
可以為屬性添加如下的一個(gè)或全部觀察器:
1.willSet在設(shè)置新的值之前調(diào)用夷野。
2.didSet在新的值被設(shè)置之后立即調(diào)用懊蒸。
3.willSet和didSet觀察器在屬性初始化過程中不會(huì)被調(diào)用。
class Samplepgm {
var counter : Int = 0 {
willSet(newTotal) {
print("計(jì)數(shù)器:\(newTotal)")
}
didSet {
if counter > oldValue {
print("新增數(shù)\(counter - oldValue)")
}
}
}
}
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
以上程序執(zhí)行輸出結(jié)果為:
計(jì)數(shù)器:100
新增數(shù):100
計(jì)數(shù)器:800
新增數(shù):700
全局變量和局部變量
計(jì)算屬性和屬性觀察器所描述的模式也可以用于全局變量和局部變量悯搔。
類型屬性
類型屬性是作為類型定義的一部分寫在類型最外層的花括號(hào)({})內(nèi)骑丸。
使用關(guān)鍵字static來定義值類型的類型屬性,關(guān)鍵字class來為類定義類型屬性妒貌。
struct StructName {
static var storedTypeProperty = " "
static var computedTypeProperty: Int {
//返回一個(gè)Int值
}
}
enum Enumname {
static var storedTypeProperty = ""
static var computedTypeProperty: Int {
//返回一個(gè)Int值
}
}
class Classname {
class var computedTypeProperty: Int {
//返回一個(gè)Int值
}
}
注意:
例子中的計(jì)算型類型屬性是只讀的通危,但也可以定義可讀可寫的計(jì)算型類型屬性,跟實(shí)例計(jì)算屬性的語法類似灌曙。
獲取和設(shè)置類型屬性的值
類似于實(shí)例的屬性黄鳍,類型屬性的訪問也是通過點(diǎn)運(yùn)算符(.)來進(jìn)行。但是平匈,類型屬性是通過類型本身來獲取和設(shè)置框沟,而不是通過實(shí)例。實(shí)例如下:
struct StudentMarks {
static let markCount = 97
static var totalCount = 0
var InternalMarks: Int = 0 {
didSet {
if InternalMarks > StudentMarks.markCount {
InternalMarks = StudentMarks.markCount
}
if InternalMarks > StudentMarks.totalCount {
StudentMarks.totalCount = InternalMarks
}
}
}
}
var studentMark1 = StudentMarks()
var studentMark2 = StudentMarks()
student1Mark1.InternalMarks = 98
print(studentMark1 > InternalMarks)
student1Mark2.InternalMarks = 87
print(studentMark2 > InternalMarks)
以上程序執(zhí)行輸出結(jié)果為:
97
87
三增炭、方法
Swift方法是與某些特定類型相關(guān)聯(lián)的函數(shù)忍燥。
在OC中,類唯一能定義方法的類型隙姿。但在Swift中梅垄,你不僅能選擇是否要定義一個(gè)類、結(jié)構(gòu)體输玷、枚舉队丝,還能靈活的在你穿件的類型(類、結(jié)構(gòu)體欲鹏、枚舉)上定義方法机久。
實(shí)例方法
在Swift語言中,實(shí)例方法是屬于某個(gè)特定類赔嚎、結(jié)構(gòu)體或者枚舉類型實(shí)例的方法膘盖。
實(shí)例方法提供以下方法:
1.可以訪問和修改實(shí)例屬性胧弛。
2.提供與實(shí)例目的相關(guān)的功能。
實(shí)例方法
在Swift語言中侠畔,實(shí)例方法是屬于繆戈特定類结缚、結(jié)構(gòu)體或者枚舉類型實(shí)例的方法。
實(shí)例方法提供以下方法:
1.可以訪問和修改實(shí)例屬性软棺。
2.提供與實(shí)例目的相關(guān)的功能红竭。
實(shí)例方法要寫在它所屬的類型的前后大括號(hào)({})之間。
實(shí)例方法能夠隱式訪問它所屬類型的所有的其他實(shí)例方法和屬性喘落。
實(shí)例方法只能被它所屬的類的某個(gè)特定實(shí)例調(diào)用茵宪。
實(shí)例方法不能脫離于現(xiàn)存的實(shí)例而被調(diào)用。
語法:
func funcName(Parameters) -> returnType {
Statement1
Statement2
......
StatementN
return parameters
}
實(shí)例:
class Counter {
var count = 0
func increment() {
count += 1
}
func incrementBy(amount: Int) {
count += amount
}
func reset() {
count = 0
}
}
//初始計(jì)數(shù)值是0
let counter = Counter()
//計(jì)數(shù)值現(xiàn)在是1
counter.increment()
//計(jì)數(shù)值現(xiàn)在是6
counter.incrementBy(amount : 5)
print(counter.count)
//計(jì)數(shù)值現(xiàn)在是0
counter.reset()
print(counter.count)
以上程序的執(zhí)行結(jié)果為:
6
0
Counter類定義了三個(gè)實(shí)例方法:
1.increment讓計(jì)數(shù)器按1遞增揖盘。
2.incrementBy(amount : Int)讓計(jì)數(shù)器按一個(gè)指定的整數(shù)值遞增眉厨。
3.reset將計(jì)數(shù)器重置為0锌奴。
Counter這個(gè)類還聲明了一個(gè)可變屬性count兽狭,用它來保持對當(dāng)前計(jì)數(shù)器值的追蹤。
方法的局部參數(shù)名稱和外部參數(shù)名稱
Swift函數(shù)參數(shù)可以同時(shí)有一個(gè)局部名稱(在函數(shù)體內(nèi)部使用)和一個(gè)外部名稱(在調(diào)用函數(shù)時(shí)使用Swift中的方法和OC中的方法極其相似鹿蜀。像在OC中一樣箕慧,Swift中方法的名稱通常用一個(gè)介詞指向方法的第一個(gè)參數(shù),比如:with茴恰、for颠焦、by等等)。
Swift默認(rèn)僅給方法的第一個(gè)參數(shù)名稱一個(gè)局部參數(shù)名稱往枣,默認(rèn)同時(shí)給第二個(gè)和后續(xù)參數(shù)名稱全局參數(shù)名稱伐庭。
以下實(shí)例中‘no1’在Swift中聲明為局部參數(shù)名稱》指裕‘no2’用于全局的聲明并通過外部程序訪問圾另。
class division {
var count: Int = 0
func incrementBy(no1: Int, no2: Int) {
count = no1 / no2
print(count)
}
}
let counter = division()
counter.incrementBy(no1: 1800, no2: 3)
counter.incrementBy(no1: 1900, no2: 2)
counter.incrementBy(no1: 11100, no2: 2)
以上程序執(zhí)行的輸出結(jié)果為:
600
950
5550
是否提供外部名稱設(shè)置
我們強(qiáng)制在第一個(gè)參數(shù)添加外部名稱把這個(gè)局部名稱當(dāng)做外部名稱使用(Swift2.0前是使用#號(hào))。
相反雕沉,我們呢也可以使用下劃線(_)設(shè)置第二個(gè)及后續(xù)的參數(shù)不提供一個(gè)外部名稱集乔。
class multiplication {
var count: Int = 0
func incrementBy(first no1: Int, no2: Int) {
count = no1 * no2
print(count)
}
}
let counter = multipication()
counter.incrementBy(first: 800, no2: 3)
counter.incrementBy(first: 100, no2: 5)
counter.incrementBy(first: 15000, no2: 3)
以上程序執(zhí)行輸出結(jié)果為:
2400
500
45000
Self屬性
類型的每一個(gè)實(shí)例都有一個(gè)隱含屬性叫做self,self完全等同于該實(shí)例本身坡椒。
你可以在一個(gè)實(shí)例的實(shí)例方法中使用這個(gè)隱含的self屬性來引用當(dāng)前實(shí)例扰路。
class calculations {
let a : Int
let b : Int
let res : Int
init(a: Int, b: Int) {
self.a = a
self.b = b
res = a+b
print("Self 內(nèi):\(res)")
}
func tot(c : Int) -> Int {
return res - c
}
func result() {
print("結(jié)果為:\(tot(c : 20))")
print("結(jié)果為:\(tot(c : 50))")
}
}
let pri = calculations(a: 600, b: 300)
let sum = calculations(a: 1200, b: 300)
pri.result()
sum.result()
以上程序執(zhí)行輸出結(jié)果為:
Self內(nèi):900
Self內(nèi):1500
結(jié)果為:880
結(jié)果為:850
結(jié)果為:1480
結(jié)果為:1450
在實(shí)例方法中修改值類型
Swift語言中結(jié)構(gòu)體和枚舉是值類型。一般情況下倔叼,值類型的屬性不能在它的實(shí)例方法中被修改汗唱。
但是,如果你確實(shí)需要在某個(gè)具體的方法中修改結(jié)構(gòu)體或者枚舉的屬性丈攒,你可以選擇變異(mutating)這個(gè)方法渡嚣,然后方法就可以從方法內(nèi)部改變它的屬性;并且它做的任何改變在方法結(jié)束時(shí)還會(huì)保留在原始結(jié)構(gòu)中。
方法還可以給它隱含得到self屬性賦值一個(gè)全新的實(shí)例识椰,這個(gè)新實(shí)例在方法結(jié)束后將替換原來的實(shí)例绝葡。
struct area {
var length = 1
var breadth = 1
func area() -> Int {
return length * breadth
}
mutating func scaleBy(res: Int) {
length *= res
breadth *= res
print(length)
print(breadth)
}
}
var val = area(length: 3, breadth: 5)
var.scaleBy(res: 3)
var.scaleBy(res: 30)
var.scaleBy(res: 300)
以上程序執(zhí)行輸出結(jié)果為:
9
15
270
450
81000
135000
在可變方法中給self賦值
可變方法能夠賦給隱含屬性self一個(gè)全新的實(shí)例。
struct area {
var length = 1
var breadth = 1
func area() -> Int {
return length * breadth
}
mutating func scaleBy(res: Int) {
self.length *= res
self.breadth *= res
print(length)
print(breadth)
}
}
var val = area(length: 3, breadth: 5)
var.scaleBy(res: 13)
以上程序執(zhí)行輸出結(jié)果為:
39
65
類型方法
實(shí)例方法是被類型的某個(gè)實(shí)例調(diào)用的方法腹鹉,你也可以定義類型本身調(diào)用的方法藏畅,這種方法就叫做類型方法。
聲明結(jié)構(gòu)體和枚舉的類型方法功咒,在方法的func關(guān)鍵字之前加上關(guān)鍵字static愉阎。類可能會(huì)用關(guān)鍵字class來允許子類重寫父類的實(shí)現(xiàn)方法。
類型方法和實(shí)例方法一樣用點(diǎn)號(hào)(.)語法調(diào)用力奋。
class Math {
class func abs(number: Int) -> Int {
if number < 0 {
return (-number)
} else {
return number
}
}
}
struct absno {
static func abs(number : Int) -> Int {
if number< 0 {
return (-number)
} else {
return number
}
}
}
let no = Math.abs(number: -35)
let num = absno.abs(number: -5)
print(no)
print(num)
以上程序執(zhí)行輸出結(jié)果為:
35
5