Stanford iOS10 公開課知識點(1)

Crazy巴旦木發表於2018-04-03

1.引數前面下劃線空格,表示呼叫時不需要寫引數名稱。
2.雖然Swift是強型別語言(強型別語言:每個變數的型別都是確定的)。但大多數情況下都能根據上下文,進行型別推導自動判斷型別,這就是Swift的強大之處,所以一般我們就省略宣告型別。
3.可選型別(Optional)只有兩種情況:有值或預設值。當有值的時候,它會有一個關聯值(另一個和這個可選一起儲存的值)。如果你在可選型別後面加上感嘆號,在可選型別有值的情況下,就可以隱式解析出關聯值,然後返還給你。但當預設值的時候強制解包,程式會崩潰。
4.在Swift中struct是一等公民,跟class是一個級別。事實上Swift中常用的“類”都是結構體,比如String,Array,Dictionary,Double都是結構體,不是類。。
那麼結構體和類的區別是什麼?兩個很重要的區別:1、類是可以整合的,結構體不可以。如果你想構造一個可擴充套件的物件,就必須用類。結構體可以隨時改成類,如果你需要擴充套件子類的話。2、類儲存在堆中,通過指標傳遞,叫引用型別。結構體儲存在棧中,通過拷貝值傳遞,把拷貝值傳遞叫做值型別。類通過引用來使用,結構體通過拷貝值來使用。這是本質的區別。
如果結構體很大的時候也會全部拷貝麼?凡是通過值拷貝傳遞的,都會採用“寫時複製”,也就是說沒有改變它的值,是不會拷貝的,這些都是在內部自動完成的。
5.為什麼在類中需要初始化引數,而在struct中不需要初始化引數呢?因為在結構體中,會自動提供一個構造器來初始化所有未初始化的屬性。
6.結構體和類的另一個區別:如果你有一個方法或者屬性,當你在某個方法內,修改它的值,必須加上mutating關鍵字,你必須告訴Swift這個方法可以修改結構體的值。這和寫時複製有關(結構體通過拷貝傳遞,但當發生修改時才會實際進行拷貝),所以它必須知道你在呼叫這個方法的時候修改了值,所以必須新增關鍵字mutating。
7.enum,列舉,它每個情況都獨一無二的,變數只能是其中一種情況,用什麼方法列舉出enum中的值呢?用switch...case...break。
8.Swift允許常量或者函式作為可選型別的關聯值,在Swift中函式也是一種普通的型別,和Double以及所有的類和結構一樣,沒有區別。
9.Swift中的閉包,是指嵌入程式碼中的函式,通過自動推導簡化引數型別,可以用$0,$1來表示引數。
10.每當你在optional後面加問號時,如果它處於已賦值狀態,那麼抓取它然後繼續,向後執行,傳送下一個東西。如果它處於空狀態,整個表示式將為空,整個一行它都返回空,如果前面用if let這行程式碼就不會被執行。
11.元組,Swift中元組中下劃線,表示無視這個引數。Range,常常表示字串從頭到尾,或者分割陣列元素。
12.原來的for(int i = 0 ; i < xxx;i++) 在swift中被替換成了for i in 0..<xxx,表示一個countableRange,遍歷這個區間值。但如果遞增的值不為1呢,或者不是整數呢?這就用到了sride,for i in stride(from:0.5,through:12.35,by:0.3),就相當於建立了一個countableRange,實際上它被稱為ClosedCountableRange,因為它遍歷到最後,相當於...而不是..<。
13.Swift中的資料結構,包括類,結構體,列舉,協議。
14.類,結構體,列舉的區別:宣告相似,雖然有不同的關鍵字,但幾乎差不多相同。唯一不同的是類指明它的父類。他們都可以有函式和屬性。列舉中不能有儲存屬性,因為列舉把它的資料儲存在關聯值中,所以它不能存出任何屬性,但是它可能有計算屬性並且它們都可以有函式。除了列舉,都可以有初始化,列舉一般都可以直接說明你想要的情況,所以不用初始化。類有繼承,結構體和列舉沒有。結構體和列舉都是值型別的,而類是引用型別。
15.值型別是什麼? 當你把它作為引數傳送它時,它就被複制了,甚至如果你僅僅把它分配給其他變數或者函式時都會拷貝,如果你把它分類給一個let,那麼它是不可變的。為了實現值型別寫入複製的行為,你必須標記所有改變值的函式為mutating,為了讓swift知道,我需要實際拷貝它,需要一個真正的副本,如果有人往它裡面寫資料的話。 引用型別是不同的,它被儲存在堆中,有一個指標指向它,當你把它傳送函式中或者將它分配給另一個變數之類的東西時,你只是在傳送指向它的指標。
16.函數語言程式設計的思想:你不想要引用型別那麼狂野(你有很多的人指向它們的物件,它們中任何一個物件在任何時間都能修改它,這給你核實你的程式的正確性帶來了很大的困難),然而你有一大堆不可變物件,你知道它們不可能被改變,並且它們的API基本上類似於數學函式,資料輸入後可預計的資料輸出,因為不會受到其他的資料影響,也不會存在多個指標引用的情況。
17.所有方法包含內部引數名和外部引數名,內部函式名用於函式的宣告,或者函式內容的實現部分,你可以在沒有外部引數名時,用下劃線來替代,這種下劃線方式我們一般都只對第一個引數使用。Why?因為有時通過函式名或者第一個引數的型別已經可以明確推斷出第一個引數是什麼,此時就沒必要寫外部引數名了,這樣顯得更清晰。對於其他引數,把引數名省略只留函式名沒什麼好處,所以只在第一個引數使用。如果只有一個引數,那麼這個引數既是外部引數名,也是內部引數名。
18.重寫和子類。對於引用型別和物件,可以重寫。你必須明確的讓Swift知道你要重寫,要用overide這個關鍵字。所以你要重寫一個父類的方法,就要用override關鍵字。可以將一個方法或者整個類標記為final,這意味著它無法被重寫,子類不允許重寫它,大部分語言都有這種語法。
19.例項方法。例項方法或者例項變數,可以通過給一個類,結構體或者列舉的例項傳送訊息來訪問。也就是給某一個具體物件,比如我可以建立它們的一個例項:我建立一個值為15.5的Double,我有了一個例項,就可以給它傳送訊息。但是型別,比如Double,String,等等,它們也可以擁有方法和變數。計算變數,沒有儲存空間,是計算得出的變數,要給型別新增方法和變數,只要將static關鍵字放在宣告語句前面就可以了,static func屬於型別,不屬於例項,是型別本身的方法。比如Double擁有不少型別方法和變數。可以通過傳送訊息給Double來訪問,不要傳送給一個例項,而是傳送給那個型別的名稱,(這裡有點不懂了),解釋一下,比如π = Double.pi。π是一個變數,一個計算變數,屬於Double這個結構體。
20.為什麼要用型別方法?我們沒法方為任何一個例項變數,因為我們沒有給例項傳送訊息,型別方法通常是類中的輔助方法,比如常量π就是一個很好的例子,還有那些和這個類本身關聯,但不屬於任何一個特定的例項或者不會真的對一個例項進行操作的方法。例如,可以有一個例項方法,或者一個例項變數叫abs,沒有引數,當你呼叫它時,它會取得這個例項的絕對值,但是型別方法需要接受一個引數,因為你傳送訊息給Double型別,所以並沒有Double,沒有Double例項參與計算。
21.屬性。什麼是屬性觀察器?屬性觀察器是一些程式碼可以在屬性改變的時候自動執行。任何時候屬性改變了,這段程式碼就會被執行,你就能準確的捕捉到屬性將要改變之前,或者屬性剛剛改變之後或者以上兩種。這隻能用於儲存屬性,比如一箇中間值,當它被改變都會執行一段程式碼。這個功能也對繼承的屬性有效,比如繼承了某些父類的屬性,可以通過屬性觀察器觀察它們的改變。如果屬性是值型別,如結構體,陣列,字典等,這些屬性觀察器會在它們指向的值被改變時,或者是包含的內容被改變時觸發。比如向陣列中新增元素會在它們指向的值被改變時,屬性觀察器會觸發並告訴你,有東西被改變了。
那麼屬性觀察器是基於什麼原理工作的呢?它們很像計算屬性那樣,比如display裡面的set get方法,你可能永遠不會(我也不知道是不是能這麼做)將屬性觀察器用於計算屬性,因為既然已經有了set語句,完全可以將程式碼放在set裡,根本不需要監視它何時被改變,因為只有在set方法裡面改變它。但是儲存屬性和繼承來的屬性不一樣,這時屬性觀察器有存在價值,所以就有了willset。willset首先把大括號放到屬性的後面,像計算屬性一樣,但並不是計算屬性。加大括號不會讓它變成計算屬性,你要在裡面加上set或get,但是如果在裡面加上willset會出現一個特殊的變數,和set計算屬性時,情況類似,叫做newValue,這個值將會被賦予給這個屬性,但是還沒賦予給它。一些儲存屬性,它還沒被設定成newValue,但是馬上就要設定了。didset中的那些程式碼在屬性被設定之後執行,在那裡特殊變數叫做oldValue,這個值是它被改變之前的值,你可以對比是否發生了變化,這些特性要用在哪裡呢?可能最重要的一個用途是在控制檢視中。比如,我是個按鈕,我的背景顏色改變了,我的背景色是繼承自繼承樹最上層的父類UIView的,每次背景色改變時,這個按鈕都想要重繪自己,所以它有一個背景色屬性,型別是UIColor,新增一個大括號,didset再跟一個大括號在這裡重繪自身。
如果某人改變了儲存屬性,我是否負責在willset或didset中做點什麼?我是否真的要去設定它?答案是否。如果被別的什麼地方修改了,你只是獲得一個機會去執行其他程式碼,你希望執行的是set前後的事情,你無需負責set這件事本身,系統已經為你做好了,所以你得到的是oldValue和newValue。

相關文章