Swift 語法學習總結

原文:http://www.cnblogs.com/hkJser/p/4618708.html

一、基礎語法

1.基礎

  1.1) swift還是使用// 和/* */ 來註釋,並且/* */允許多行註釋.
  1.2) swift使用print和println打印,它的傳參是一個泛型,幾乎所有類型都是可打印的.
  1.3) swift在語句後面加分號與否都是正確的,但是swift偏好的風格是不在結尾處加分號的.如果有多個語句,必須用分號隔開.
  1.4) 在一個數字中庸下劃線(_)會被忽視,方便認出大數值的的數字,也可以在前面補零.
  1.5) swift不允許在不同種類型間做加減乘除,要先做類型轉換或運算符重載.
  1.6) typealias 可以爲一個類型指定另外一個名字,這樣可以清晰的表達類型的意義.typealias newType = OldTypeName
  1.7) assert 斷言表示自己拋出異常,assert 第一個參數表示 通過而不拋異常的條件,第二個參數表示提示,第二個參數可以沒有
  1.8) swift中的 = 賦值運算符沒有返回值,所以不會犯 if a = 3 {}這樣的錯誤了,運算符前後加空格,以免xcode不能識別
2.變量
  2.1) let 定義常量,var 定義變量,let定義的必須在聲明時指定初始值,普通的var聲明也必須賦初始值.
  2.2) let 聲明的變量不可再改變,而var變量可以再改變,但是你不能再聲明一個已經聲明的常量或變量.
  2.3) 可以在一行同時聲明多個常量或變量,用逗號隔開;如果每個常量對應一個var或let只需要用分號隔開即可.
  2.4) 每個常量和變量都一定會有固定的類型,如果沒有指定類型,swift會根據後面的賦值類型來推斷.
  2.5) swift的命名不能使用保留字和箭頭/開頭不能用數字,沒有其它任何規定,甚至都可以使用小狗小貓命名.
  2.6) 如果你想使用關鍵字來命名是不允許的,但是你可以在前後加上``來命名,比如`let`,非關鍵字加``命名也可以的.
  2.7) swift裏可以聲明元組,類型類似於(Int, String),你可以用var聲明也可以用let聲明,裏面兩個都會是變量或者常量
  2.8) 而元組的方式和直接分開聲明兩個變量和常量沒多大區別,你可以把其中的變量拿出來單獨用或當元組用,混合用也可以.
  2.9) 可以用元組名直接通過下標索引直接來訪問元組裏對應的值,比如aaa.0 aaa.1
  2.10) 你可以在元組中跟元素命名,比如(code:404,message:"Not Found"),然後你就可以用aaa.code 和 aaa.message來訪問
3.類型
  3.1) int型的UInt8和Int32 都可以通過min和max來取最大值和最小值
  3.2) Double是64位浮點數,Float是32位浮點數,對小數自動推斷是Double類型,除非是指定過類型的
  3.3) 可以跟指定爲浮點類型的常量或變量賦一個整數值但是不能是整數變量,它會自動轉換成浮點數.
  3.4) 顯示指定類型的變量或常量不能跟它賦值一個不同類型的值,它不能做自動轉換,除了跟浮點類型賦值一個整數數值
  3.5) 在指定類型後加一個?表示可選類型,它的意思是它可能爲沒有值爲nil,然後你可以通過可選綁定或者判斷是否爲空來使用它.
  3.6) 如果是一個class的可選類型,你可以通過?.訪問它的屬性和方法,它是通過前者是否會相應後面的方法,如果能響應則執行,不能則返回nil
  3.7) ?其實是個語法糖,比如String?類型等價於Optional<String>類型,只是方便寫而已,他和String類型本質是不同的
  3.8) 如果你不想用判斷是否爲空或者用可選綁定或者用.?來訪問它,你可以用最直接最簡單的!強制解包來使用,但前提是能保證非空
  3.9) 如果一個可選量沒有值又強制解包會報錯,一個可選類型會隱式賦值爲nil,你也可以在使用中賦值爲nil
  3.10) 之所以需要有可選類型是因爲swift是類型絕對安全的語言,它需要你在使用變量時一定有值,但是這種可選類型太麻煩,所以產生了!類型,!類型本質應該就是可選類型
  3.11) 聲明爲!可選類型,也可以不做初始化,它相當於你在每次使用可選類型的時候加上了!進行強制解包,你就不需要再自己加!了,你需要自己保證它不爲空,否則使用會出錯
4.字符串
    4.1) ... 表示閉區間/ ..< 表示開區間, == 表示值相等/=== 表示引用相同, + 可以直接加字符串或數組
  4.2) swift中的string是值類型,它在做常量變量賦值或函數中進行傳遞時都會做值拷貝,都是一個新的副本,swift只有在必要的情況下做拷貝
  4.3) 可以用for in 遍歷字符串,用 count全局函數計算字符數,用isEmpty屬性判斷是否是空字符串,有hasPrefix判斷前綴(後綴等)
  4.4) 可以用startIndex和endIndex獲取開始和結束下標,用數組和下標的形式訪問單個字符;還可以通過\()的方式生成字符串
5.數組
    5.1) swift中的數組可以用[String]和Array<String>來聲明,它們是同一個意思,賦值也直接用中括號[]表示就可以了,裏面的值需要是同一個類型
  5.2) array 有count/isEmpty等屬性,有append/insert/remove等方法,它可以直接 + 一個數組,它可以通過下標和下標區間來取值,區間取到的是一個數組
  5.3) for item in shoppingList / for (index, value) in enumerate(shoppingList) 兩種遍歷方式,後面一種會知道下標
  5.4) 可以通過[Double](count: 3, repeatedValue: 3.3) / Array(count: 3, repeatedValue: 2.5) 初始化一個數組
  5.5) 數組也是值傳遞,如果把數組a賦值給數組b,a和b就是兩份拷貝,修改相互不會有影響
6.字典
  6.1) 字典是通過 [String : String] / Dictionary<String, String> 聲明的,形式也是用[a:b,c:d]這種形式,通過鍵訪問值
  6.2) 可以直接通過a[b] = c 這種方式增加一個鍵值對,通過updateValue和removeValueForKey來增加刪除鍵值對
  6.3) 可以用for (airportCode, airportName) in airports / for airportCode in airports.keys 遍歷鍵值對或鍵或值
  6.4) 可以直接賦值 [:] 來清空字典,鍵值是可以爲Int的;和string,array一樣,dictionary也是值拷貝
7.Set
  7.1) 用Set<Int> 聲明Set,和數組一模一樣跟它賦值,也可以通過賦值[]清除,也必須是同一類型,也有insert/contains方法,isEmpty屬性
  7.2) Set也有for in 遍歷,有取兩個集合的差交等做做排列的方法,也有判斷子集超集等方法
8.For循環
  8.1) for index in 1...5 的這個index只是在當前這個循環的作用域內,如果for循環外面也有一個index,隨便修改也不會和它又什麼影響
  8.2) for _ in 1...10 如果不需要循環的這個索引可以用下劃線_代替,在swift中只要不需要那個值的一般都可以用_代替
  8.3) for var index = 0; index < 3; ++index 這種for循環也還是可以的
9.Switch語句
  9.1) swift 中的switch必須窮舉所有的可能,否則必須加default,窮舉的時候在一個case後面可以放很多可能值,用逗號隔開就好
  9.2) 窮舉可以是用...和..<表示的一個區間,對於元組可以一個用_通配符,另一個匹配,或者兩個都匹配,或者兩個都是區間(只有一個元素也可以做值綁定)
  9.3) 做統配的時候可以用var x/let x,或 let (x,y) 進行值綁定,其中var聲明的可以修改
  9.4) 當做let 做值綁定的時候可以在後面加上 where做條件判斷.switch 不需要用break防止穿透,但是它還是會去下一個case判斷條件去匹配,使用break還是可以直接跳出switch
  9.5) 在switch同樣可以使用break/continue跳出一個標籤

二、高級語法

1.函數
  1.1 func funcNmae()->(){} 這樣就定義了一個函數,它的參數爲空,返回值爲空,如果有參數和返回值直接寫在兩個括號裏就可以了
  1.2 參數需要指明類型,而如果沒有返回值可以不寫->(),返回值只需要寫返回類型,如果寫了返回名稱,可以在函數調用後的值用點語法訪問
  1.3 在參數名稱前可以加上外部參數名,調用的時候就可以帶上它了,如果外部參數名和內部參數名相同則可以直接在內部參數名前加#即可
  1.4 如果跟參數設置一個默認值,則swift會自動加上外部參數名,如果不想有在前面用下劃線就可以_,如果默認值參數不在最後則不能省略,在傳參時傳一個下劃線進去就可以
  1.5 在最後一個參數後面加...代表是這個參數是可變參數並且類型就是它,參數個數至少是0個,在函數內可以使用for in 這個參數獲得 這些參數
  1.6 每個參數前面其實有一個隱藏的關鍵字let,如果想讓參數可變(可賦值)則需要加上var關鍵字,不過也只是能賦值,因爲是值拷貝所以不能修改外部參數的實際值,如果要變成地址傳遞,需要在參數前加inout 關鍵字,而實參需要加上& ,
  1.7 swift中函數其實也只是中類型,函數名就是變量名,比如let func1 : () -> () 聲明的就是個無參數無返回值的函數類型,所以如果一個函數返回一個函數的話和返回一個普通變量沒什麼區別
2.閉包
  2.1 閉包代表了一段程序代碼,{ (傳入參數) -> 返回值的類型 in ... 表達式 ... },函數只是閉包的一個特例
  2.2 閉包可以推斷返回類型,所以可以省略->返回值類型,參數類型也可以推到,所以參數類型也不要,括號也可以去掉,如果閉包只有一個表達式直接可以省略掉return關鍵字,因爲我們可以用$0/$1簡寫參數,所以參數也可以省略掉.
  2.3如果閉包是函數最後一個參數,則可以去掉小括號,直接用大括號裏的內容,不過需要大括號緊接着寫,叫尾隨閉包
  2.4 內層返回函數會捕獲外層的變量的值,當內層函數返回後,外層函數的內部變量並不會釋放內存,它的變量的值會跟着內部函數的執行而變化
3.枚舉
  3.1 用enum CompassPoint{ case North, South , East, West}定義枚舉,可以不用逗號,和聲明語句一樣分開用多個case寫就可以了
  3.2 可以用元組來設定枚舉對應每項中的值,並可以用switch case 中的值綁定來判斷,
  3.3 枚舉類型如果初始化爲Int類型,它的下一項也會有一個加1的原始值,不過枚舉直接複製成string都可以的
4.結構體
  4.1 結構題的屬性必須初始化,必須有默認值或者通過構造器init
  4.2 結構體本身是值傳遞,如果一個結構體賦值給另外一個結構體了也是兩份拷貝,互相修改不會有影響
  4.3 如果一個結構體用let聲明瞭,那麼它內部的值就不能再做修改了,var聲明的結構體才能修改
  4.4 但是class不同,對象的賦值會是同一份引用,修改會影響到另外一個對象,但是let 聲明的變量也是不能賦值的,只是能修改它內部的值而已
5.屬性(成員變量)
  5.1 結構體/類在初始化的時候成員變量一定要有值,如果你沒有給出初始化方法,則默認有一個包含所有必須初始化的的init方法,如果你提供了,默認了就沒有了
  5.2 (延遲屬性)用let聲明的成員變量,就不能再修改了,如果是一個耗時的屬性比如值是一個自定義對象,可以加上lazy屬性,它只有在用到的時候纔會對這個屬性做初始化,避免不要的消耗(延遲屬性)
  5.3 (計算屬性)有的屬性是根據其它的屬性計算出來的,並不是一個必須的屬性,只是讓使用的時候方便了些,在屬性定義後面加上set/get方法,get方法需要返回一個值,set方法有一個參數,用來設置其它屬性,如果不要參數就不要寫參數外面的括號,它就有一個默認的參數newValue
  5.4 如果只有get方法就是隻讀屬性,只讀屬性swift提供了一種簡寫方式,直接把返回語句寫在最外面的大括號裏就可以了
  5.5 swift提供了屬性監聽方法:willSet和didSet,兩個都是一樣有一個參數,分別將要設置的值,和屬性過去的值,同樣你如果不提供參數,會用兩個默認的newValue和oldValue.這兩個方法和set/get方法並列,在didSet方法中可以直接修改(調整)屬性的值,但是這兩個方法不能和set/get方法共存
  5.6 swift中有類別屬性,enum/struct 用關鍵字static,class就用class關鍵字,在class中let 聲明的需要直接賦初始值,var聲明的必須用get方法return,因爲swift不允許class儲存類屬性,而enum/struct可以
6.函數(成員方法)
  6.1 class中的函數都不需要加上外部參數,因爲除了第一個參數都默認加上了#符號,不過這只是swift幫你做了點事情而已,它並沒有在語法上強制你做什麼,你想爲第一個參數加上外部參數也行,都用_代替默認的外部參數都可以
  6.2 在swift裏self.x不代表會調用setX/getX方法,所以直接可以在set/get方法裏這麼用.
  6.3 在struct和enum中,成員方法不允許修改成員變量,如果要修改需要加上mutating關鍵字,但是如果聲明的結構體變量是一個let常量的話,這個方法也是不允許調用的.
  6.4 在struct和enum中你可以在mutating方法中直接跟self賦值成另外一個變量
  6.5 在struct和enmu中用static標識一個方法是類方法,而class中用class關鍵字
7.角標(subscript)
  7.1 重寫subscript,類似於subscript(index: Int) -> Int{},裏面寫set/get方法,和聲明變量,根據傳參和返回值來確定下標的類型和返回值,重寫了這個方法這個對應的類型就可以用角標了.
  7.2 subscript方法參數的個數對應角標的個數,例如兩個參數:mar[2,3]
8.繼承
  8.1 swift中沒有基礎類,所有不繼承其它類的的類都是基礎類,重寫父類中init方法,要先調用super的init方法,然後再在後面修改屬性的值,訪問屬性直接用屬性名字就可以了,不用用self等.
  8.2 要重寫屬性和重寫方法類似,直接加個override就好了,在重寫的set/get方法也可以調用super對應的屬性值,或設置值都可以.
  8.3 覆蓋了didSet屬性監視器就不能再覆蓋set/get方法了,跟方法或屬性加上final關鍵字可以防止被子類覆蓋
9.初始化(init)
  9.1 init方法和普通方法一樣,你需要在init方法中把每個必須要賦值的屬性都賦值,否則會出編譯錯誤,init方法會給每個參數加上#,不要它的話可以用_,在方法內部用self訪問,也可以不用
  9.2 如果你自定義了init方法,那麼swift會不再提供默認的init方法,你可以自己寫一個init方法,init方法帶不帶參數什麼都是可以的,自己決定就行
  9.3 如果你想一個init方法中調用另一個init方法,需要加上一個convenience關鍵字,在這個init方法裏就可以調用另一個init方法了
  9.4 在子類繼承父類的時候,首先需要初始化子類的成員變量,然後才能調用super的init方法初始化父類的屬性,最後可以修改子類和父類的屬性,如果這個屬性是父類的,在子類中也是用self訪問,因爲這個屬性已經是它自己的了
  9.5 如果子類一個init方法都沒有提供,那麼子類繼承父類所有的構造器,可以用父類的init方法初始化
  9.6 在初始化屬性的時候,可以用閉包實現,只要在複製的=後面加上{},你們寫return和其它語句,最後在{}後面加一個()表示閉包立刻執行,閉包和屬性的set方法是類似的,只是在最開始提供的
10.銷燬方法(deinit)
  10.1 deinit方法會在對象銷燬的時候調用,可以打印判斷它時候銷燬
11.內存管理(ARC)
  11.1 可選類型或者普通類型屬性只要對一個對象有一個引用,它的這個對象的引用計數就要加1,如果兩個對象相互引用就會產生引用循環,所以需要跟其中的一個屬性用關鍵字weak聲明爲弱引用,就是可以設置爲nil
  11.2 一般用weak聲明的用可選類型,因爲它引用的可能爲nil,如果你在調用的時候能確定它是有值的,你可以聲明爲unowned的普通類型,它的效果是如果你能保證調用這個屬性時不爲nil時,swift建議用unowned,其它都和weak一樣的
12.可選鏈(Optional Chaining)
  12.1 對於一個可選類型的屬性可以用?.和!.來訪問,如果確定有值可以用a!.b!.c!.d,如果不確定有值可以用a?.b?.c?.d
13.類型轉化
  13.1 可以用 a is b 來判斷對象a是否是b類型,返回值是一個boolean類型的值
  13.2 as 可以把普通類型轉化,比如double,int,cgfloat之類都可以用它轉化
  13.3 可以用 as? 把之類轉化成父類,它的結果可以是nil或者轉型成功,所以結果是一個可選類型,轉化成功後用?.來訪問方法或屬性,也可以做可選綁定.
  13.4 如果一個對象一定可以轉化成功,則可以用as!轉化,如果轉化不成功會報運行時錯誤,比如在一個數組中全是animal,但是聲明時是anyobject就可以這樣用.
14.擴展/協議(categories,extension,protocol)
  14.1 swift的extension沒有名稱,它是擴展到所有的實體類的,它不可以增加成員屬性,但是可以增加計算屬性
  14.2 可以在protocol中聲明屬性和方法,可以定義屬性時候是隻讀的或者是可讀可寫的
  14.3 可以讓一個extension繼承一個protocol,在裏面實現對應的方法
  14.4 協議的類型是protocol<protcl1,protcl2>
15.泛型
  15.1 可以在func或struct後面跟上<T1,T2>,在參數中就可以聲明參數類型爲這個類型,完全可以把它看做是一個類型
16.運算符重載
  16.1 在swift中運算符可以重載,方法名就是運算符號,參數的個數和類型是根據它是幾目運算符和運算符兩邊對應的參數類型決定的.

三、補充總結

      1. 可選類型是一種類型,String?就是Optional<String>,所以函數參數也可以聲明爲它
      2. a??b??c 如果a有值返回a,a爲nil返回b,b也也爲nil,前面的整體結果就是nil返回c.條件是??前面的都必須是optional的,??後面的類型必須和??前面的一致,結果等價於三目運算符a!=nil?a!:b
      3. 遵從GeneratorType協議的對象有一個next方法可以用來遍歷,你可以自定義generator遵循generatorType協議,自己就可以根據這個方法做循環,你在next方法中寫好遍歷的順序就好.
      4. 遵從SequenceType協議的對象可以用for in來循環,每個SequenceType對象裏面包含對應着一個generator,也可以獲取generator後做while循環,也可以直接寫for in循環,for in出來每項的值就是generator中next方法的返回值
      5. 區間運算符...和..<其實是Range<T>類型的對象,這個對象有一個generate方法,返回的是RangeGenerator<T>類型結構體,它遵循GeneratorType協議,所以...和..< 也能做for in 循環
      6. 數組過濾方法可以用閉包,如:oldArray.filter{ $0 > 30 },數組還有個根據數組值計算的的方法,oldArray.reduce(1,combine: {$0 + $1}) 結果就是1和數組中的每個元素相加
      7. Int和string都有map方法,someName.map{name in "Hello,\(name)"}??"Hello world!" name是個可選類型,你不需要做可選綁定,如fil果name是nil,這個map方法返回的值也是nil
      8. 函數的柯里化就是多參函數變成一個參數調用的返回值是函數,再調用的這個函數傳入第二個參數,這中間得到的函數叫外部這個函數的偏函數,函數柯里化只需要把函數的多個參數分別寫在不同的括號裏就可以了
      9. 在類命名訪問成員方法,得到的是一個可以函數柯里化的函數,第一個參數是類對應的對象,後面的參數就是這個函數應該有的參數
      10. swift的枚舉可以有相關值(就是傳參),有相關值的兩個枚舉值不能用==比較,需要自己重載==運算符,而普通的枚舉是可以通過==比較的
      11. 枚舉是可以有原始值的(默認值),可以是String,Character,Int,Float類型的,如果是Int後面的枚舉會遞增,通過rowValue可以獲取到原始值
      12. 由於swift初始化方法的安全檢查太嚴格,在設置類似於數據源數組的時候可以用lazy 聲明,並用閉包返回值
      13. Any表示任何類型除了方法類型,AnyObject表示任何class類型的實例
      14. 在協議前加@objc表示協議可選,它只對class有效;在方法和屬性前加optional表示屬性和方法可選protocol<SomeProtocol,AnotherProtocol>就可以表示遵循這兩個協議的對象


發佈了47 篇原創文章 · 獲贊 16 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章