Swift學(xué)習(xí)總結(jié)
協(xié)議
協(xié)議是方法的集合,它可以把看似不想關(guān)的對象的公共行為放到一個協(xié)議中丸逸。
協(xié)議在Swift開發(fā)中大致有三種作用:
1.能力 - 遵循了協(xié)議就意味著具備了某種能力某饰;
2.約定 - 遵循了協(xié)議就一定要去實(shí)現(xiàn)協(xié)議中的方法儒恋;
3.角色 -一個類可以遵循多個協(xié)議,一個協(xié)議可以被多個類遵循黔漂,遵循協(xié)議就意味著扮演了某種角色诫尽,遵循多個協(xié)議就意味著可以扮演多個角色。
Swift中的繼承是單一繼承(一個類只能有一個父類)炬守,如果希望讓一個類具備多重能力可以使用協(xié)議來實(shí)現(xiàn)牧嫉。
protocol Singsongs{
func sing()
}
protocol Teach{
func teach()
}
class Student:singSongs{
var name:String
init(name:String){
self.name = name
}
func sing(){
print("\(name)正在唱歌")
}
}
class Teacher:Singsongs,Teach{
func teach(){
print("老師正在教學(xué)生唱歌")
}
func Singsongs(){
print("老師正在唱歌")
}
}
協(xié)議擴(kuò)展
可以在協(xié)議擴(kuò)展中給協(xié)議中的方法提供默認(rèn)實(shí)現(xiàn),也就是說如果某個類遵循了協(xié)議但是沒有實(shí)現(xiàn)這個方法就直接使用默認(rèn)實(shí)現(xiàn)劳较,那么這個方法也就相當(dāng)于是一個可選方法(可以實(shí)現(xiàn)也可以不實(shí)現(xiàn))
在定義子類的時候必須先寫父類驹止,協(xié)議無關(guān)緊要
class Student:Human,Listen,Speak,Read,Write{
var name:String
init(name:String){
self.name = name
}
func listen(){
...
}
...
...
}
依賴倒轉(zhuǎn)原則(面向協(xié)議編程)
1.聲明變量的類型時應(yīng)該盡可能使用協(xié)議編程
2.聲明方法參數(shù)類型的時候應(yīng)該盡可能使用協(xié)議類型
3.聲明方法返回類型時應(yīng)該盡可能使用協(xié)議類型
協(xié)議中全是抽象概念(只有聲明沒有實(shí)現(xiàn)) 遵循協(xié)議的類可以各自對協(xié)議中的計算屬性和方法給出自己的實(shí)現(xiàn)版本 ,這樣當(dāng)面向協(xié)議編程時就可以把多態(tài)的優(yōu)勢發(fā)揮到淋漓盡致 可以寫出更通用更靈活的代碼(符合開閉原則)
開閉原則
實(shí)現(xiàn)開閉原則最關(guān)鍵有兩點(diǎn):
1.抽象是關(guān)鍵(在設(shè)計系統(tǒng)的時候一定要設(shè)計好的協(xié)議)观蜗;
2.封裝可變性(橋梁模式 - 將不同的可變因素封裝到不同的繼承結(jié)構(gòu)中)
接口(協(xié)議)隔離原則:協(xié)議的設(shè)計要小而專不要大而全
協(xié)議的設(shè)計也要高度類聚
結(jié)構(gòu)
結(jié)構(gòu)大體上和類相仿臊恋,但是也有許多區(qū)別
struct Student{
var name:String
var age:Int
func study(courseName:String){
print("\(name)正在學(xué)習(xí)")
}
}
區(qū)別1: 結(jié)構(gòu)的對象是值類型, 類的對象是引用類型
值類型在賦值的時候會在內(nèi)存中進(jìn)行對象的拷貝
引用類型在賦值的時候不會進(jìn)行對象拷貝只是增加了一個引用
結(jié)論: 我們自定義新類型時優(yōu)先考慮使用類而不是結(jié)構(gòu)除非我們要定義的是一種底層的數(shù)據(jù)結(jié)構(gòu)(保存其他數(shù)據(jù)的類型)
值類型的結(jié)構(gòu)
區(qū)別2: 結(jié)構(gòu)會自動生成初始化方法
區(qū)別3: 結(jié)構(gòu)中的方法在默認(rèn)情況下是不允許修改結(jié)構(gòu)中的屬性除非加上mutating關(guān)鍵字
//創(chuàng)建一個學(xué)生對象,然后用stu去引用它墓捻,所以此時學(xué)生對象引用計數(shù)為1
var stu:Student? = Student()
//此處沒有創(chuàng)建新的學(xué)生對象抖仅,原來的學(xué)生對象引用計數(shù)加1
var stu1 = stu
var stu2 = stu
var stu3 = stu
stu1 = nil
stu2 = nil
stu3 = nil
stu = nil
//附一個nil,引用計數(shù)-1當(dāng)引用計數(shù)為0砖第,ARC自動清理內(nèi)存釋放學(xué)生對象
//ARC即時性的內(nèi)存清理優(yōu)于Java中的Garbage Collection(垃圾回收)
var stu1:Student? = Student()
//強(qiáng)引用(strong(默認(rèn)))會增加引用計數(shù)撤卢,弱引用(weak)修飾的引用不會增加引用計數(shù)
weak var stu2 = stu1
weak var stu3 = stu2
stu1 = nil
//如果想釋放內(nèi)存 程序員可以手動將一個引用賦值為nil
var stu:Student?
func foo(){
//stu是一個局部變量/常量 在函數(shù)調(diào)用結(jié)束后局部變量就消失了
//所以學(xué)生對象的引用計數(shù)也就變成0了 所以會被ARC釋放掉
let stu = Student()
print(stu)
}
foo()
//創(chuàng)建任何子類對象的時候一定是先創(chuàng)建了父類對象
//引用轉(zhuǎn)移(會導(dǎo)致原來對象上的引用計數(shù)-1 新對象引用計數(shù) + 1)
var stu1: Person = Student()
var stu = Student()
var tea = Teacher()
自動釋放池
//通過向autoreleasepool函數(shù)中傳入一個閉包來實(shí)現(xiàn)
//autoreleasepool { () -> () in
//自動釋放池中的對象引用在池的邊界會收到引用計數(shù)-1的消息
//將來做iOS開發(fā)是某個地方會創(chuàng)建很多的臨時對象
//那么最好在此處設(shè)置一個自動釋放池避免內(nèi)存瞬時峰值過高造成閃退
// let stu = Student()
//}
離開自動釋放池時 stu1會收到引用計數(shù)-1的消息 stu2也會收到引用計數(shù)-1的消息
如果程序中出現(xiàn)了類與類之間雙向關(guān)聯(lián)的關(guān)系 必須要將其中一端設(shè)置為weak引用
否則將會形成循環(huán)引用導(dǎo)致ARC無法釋放內(nèi)存
如果允許使用可空類型,通常使用weak來破除循環(huán)引用梧兼。如果不能使用可空類型放吩,就使用unowned來破除
如果員工對象關(guān)聯(lián)的部門對象被釋放了,如果還要員工對象去操作它所關(guān)聯(lián)的部門對象將導(dǎo)致程序崩潰
EXC_BAD_ACCESS
泛型 (generic)
讓類型不再是程序中的硬代碼(寫死的東西)
func bubbleSort<T: Comparable>(array: [T]) -> [T] {
var newArray = array
for i in 0..<newArray.count - 1 {
var swapped = false
for j in 0..<newArray.count - 1 - i {
if newArray[j] > newArray[j + 1] {
mySwap(&newArray[j], &newArray[j + 1])
swapped = true
}
}
if !swapped {
break
}
}
return newArray
}
// 定義一個虛擬類型T, 調(diào)用函數(shù)時根據(jù)傳入的參數(shù)類型來決定T到底是什么
func mySwap<T>(inout a: T, inout _ b: T) {
let temp = a
a = b
b = temp
}
泛型限定
// <T: Comparable>限定T類型必須是遵循了Comparable協(xié)議的類型
func myMin<T: Comparable>(a: T, _ b: T) -> T {
return a < b ? a : b
}
let array1: Array<Int> = [23, 45, 99, 12, 68, 51, 70, 66]
let array2 = bubbleSort(array1)
print(array1)
print(array2)
異常處理(Error Handling)
如果一個方法拋出了異常 那么在聲明方法時必須要寫上throws關(guān)鍵字
throws關(guān)鍵字是提醒方法的調(diào)用者方法可能會出狀況 調(diào)用時要寫try
init(num: Int, den: Int) throws {
_num = num
_den = den
if _den == 0 {
// 如果程序中出現(xiàn)問題就拋出錯誤(異常)
// 被throw關(guān)鍵字拋出的必須是遵循ErrorType協(xié)議的東西
throw FractionError.ZeroDenominator
}
else {
simplify()
normalize()// 如果一個方法拋出了異常 那么在聲明方法時必須要寫上throws關(guān)鍵字
// throws關(guān)鍵字是提醒方法的調(diào)用者方法可能會出狀況 調(diào)用時要寫try
init(num: Int, den: Int) throws {
_num = num
_den = den
if _den == 0 {
// 如果程序中出現(xiàn)問題就拋出錯誤(異常)
// 被throw關(guān)鍵字拋出的必須是遵循ErrorType協(xié)議的東西
throw FractionError.ZeroDenominator
}
else {
simplify()
normalize()
}
}
}
func add(other: Fraction) -> Fraction {
// 如果能夠確保方法調(diào)用時不出異常那么可以在try關(guān)鍵字后加!
// 這樣就可以在不寫do...catch的情況下調(diào)用可能出狀況的方法
return try! Fraction(num: _num * other._den + other._num * _den, den: _den * other._den)
}
如果能夠保證代碼不出錯可以在try后面加!
如果不確定代碼是否出錯可以在try后面加?
需要注意的是有?的地方會產(chǎn)生Optional(可空類型)
稍后可能還需要對可空類型進(jìn)行拆封, 拆封方式有二:
- 不安全的做法: xxx!
- 安全的做法: 用if let = xxx { }進(jìn)行拆封
func foo() {
let f1 = try? Fraction(num: 3, den: 0)
let f2 = try? Fraction(num: 0, den: 9)
if let a = f1, b = f2 {
let f3 = a + b
print(f3.info)
}
else {
print("無效的分?jǐn)?shù)無法進(jìn)行加法運(yùn)算")
}
}
foo()
對于可能出狀況的代碼要放在do...catch中執(zhí)行
在可能出狀況的方法前還要寫上try表示嘗試著執(zhí)行
如果在do中沒有出現(xiàn)任何狀況那么catch就不會執(zhí)行
如果do中出現(xiàn)了狀況代碼就不會再向下繼續(xù)執(zhí)行而是轉(zhuǎn)移到catch中
在do的后面可以跟上多個catch用于捕獲不同的異常狀況 但是最多只有一個catch會被執(zhí)行
//do {
// let f1 = try Fraction(num: 3, den: 4)
// let f2 = try Fraction(num: 0, den: 9)
//
// print(f1.info)
// print(f2.info)
//
// let f3 = f1 + f2
// print(f3.info)
// let f4 = f1 - f2
// print(f4.info)
// let f5 = f1 * f2
// print(f5.info)
// let f6 = try f1 / f2
// print(f6.info)
//}
//catch FractionError.ZeroDenominator {
// print("瓜西西的, 分母不能為0!!!")
//}
//catch FractionError.DivideByZero {
// print("卵球了, 除以0是不行的!!!")
//}
//catch {
// print("出錯了! 我也不知道什么問題")
//}
計算機(jī)的硬件組成
計算機(jī)的硬件由五大部件構(gòu)成:
運(yùn)算器羽杰、控制器渡紫、存儲器、輸入設(shè)備考赛、輸出設(shè)備
運(yùn)算器 + 控制器 => CPU (中央處理器)
存儲器 => 內(nèi)存 (RAM - Random Access Memory)
程序員可以使用的內(nèi)存大致分為五塊區(qū)域:
棧 (stack) - 我們定義的局部變量/臨時變量都是放在棧上
- 特點(diǎn): 小惕澎、快
堆 (heap) - 我們創(chuàng)建的對象都是放在堆上的 - 特點(diǎn): 大、慢
靜態(tài)區(qū) (static area) - 數(shù)據(jù)段 - 全局量
- 只讀數(shù)據(jù)段 - 常量
- 代碼段 - 函數(shù)和方法
Swift語言階段總結(jié)
經(jīng)過了三周的學(xué)習(xí)颜骤,把Swift的語法過了一遍唧喉,對這門編程語言也有了大致的了解了,雖然沒有什么基礎(chǔ)忍抽,但勉強(qiáng)還是跟上了進(jìn)度(應(yīng)該是跟上了吧>o<)八孝,不過呢,最大的毛病是總感覺能看懂怎么用鸠项,但自己一寫就不行了唆阿。可能是對某些語法理解不夠深的原因吧锈锤,不過這也再次提醒了我驯鳖,畢竟算不上高智商,不經(jīng)過無數(shù)的練習(xí)久免,是學(xué)不會的浅辙。而我現(xiàn)在的努力程度,貌似差的有點(diǎn)多阎姥。记舆。
下一周又將迎來一個新的階段,雖然還不知道難度怎么樣呼巴,但是現(xiàn)在我也只能選擇向前泽腮,沒有退縮的余地御蒲。等以后成功的時候,總會感謝現(xiàn)在拼搏的自己诊赊,加油厚满!