簡介
特點
(1)優(yōu)于OC,快速,安全
(2)取消了預(yù)編譯指令包括宏定義(OC用的太多了)
(3)取消了OC指針和不安全訪問的使用(看不到星星了)
(4)舍棄 Objective-C 早期應(yīng)用 Smalltalk 的語法,全面改為點語法
(5)3.0中對Foundation框架做了很多改變,去除了NS,將絕大部分class轉(zhuǎn)換成struct結(jié)構(gòu)體(為了考慮性能和安全性,絕大部分使用結(jié)構(gòu)體來代替以前的類,但是在實際使用感覺不到)
(6)可以使用現(xiàn)有的 Cocoa 和 Cocoa Touch 框架
, 以前是OC調(diào)UIKit,現(xiàn)在就是Swift調(diào)UIKit,這點事沒問題的
(7)Swift因為語法的嚴(yán)謹(jǐn)性可以讓很多錯誤提前遇到,這樣很少出現(xiàn)bug讓程序停在main導(dǎo)致無法找到
(8)@UIApplicationMain是程序的入口
(9)只有.h沒有.m
(10)所有的代碼都包括在{}里,默認(rèn)方法func都有縮進(jìn)!
(11)語法的allocinit替換成()PlayGround
(1)可以看蘋果官方自帶的tips和100個tips,都在Placground來使用基礎(chǔ)點
(1)不適用self. 在閉包或者編譯器提示的時候再使用
(2)分號是用來分割語句的,如果一行洗很多,就可以加分號,一般時候可以不加
(3)#function打印執(zhí)行的函數(shù)
(4)添加標(biāo)記用到// MARK: - 選擇,如果是接下來要做的可以用// TODO:和// FIXME:這些非常有用
一、常量和變量
定義
let 定義常量,一經(jīng)賦值不允許再修改
var 定義變量,賦值之后仍然可以修改
常量和變量的細(xì)節(jié)使用 : 類型,僅僅只定義類型
常量有一次設(shè)置的機會
應(yīng)該盡量先選擇常量,只有在必須修改時,才需要修改為 var
// 定義常量并且直接設(shè)置數(shù)值let x: Int = 10// 常量數(shù)值一經(jīng)設(shè)置,不能修改,以下代碼會報錯// x = 30let y: Int// 常量有一次設(shè)置的機會,以下代碼沒有問題,因為 `y` 還沒有被設(shè)置數(shù)值y = 10// 一旦設(shè)置之后,則不能再次修改,以下代碼會報錯,因為 `y` 已經(jīng)被設(shè)置了數(shù)值// y = 50print(x + y)// 變量設(shè)置數(shù)值之后,可以繼續(xù)修改數(shù)值var z: Intz = 100z = 200print(x + y + z)
自動推導(dǎo)
Swift 能夠根據(jù)右邊的代碼,推導(dǎo)出變量的準(zhǔn)確類型
只有相同類型的值才能夠進(jìn)行運算
// 整數(shù)默認(rèn)的類型是 Intlet intValue = 200// 小數(shù)的默認(rèn)類型是 Doublelet doubleValue = 10.5// 如果要對不同類型的數(shù)據(jù)進(jìn)行計算,必須要顯式的轉(zhuǎn)換print(intValue + Int(doubleValue))print(Double(intValue) + doubleValue)
注意:Swift對類型要求異常嚴(yán)格,任何不同類型的數(shù)據(jù)不能直接運算(哪怕是Int和Double),不會做一些自動的轉(zhuǎn)換來轉(zhuǎn)換成Double。Swift不存在基本數(shù)據(jù)類型,Int和Double都是結(jié)構(gòu)體其實,強轉(zhuǎn)用Double(x)完成,或者在定義的時候直接指定變量的類型let x : Double = 10;(很少使用)
二、控制流
if
Swift 中沒有 C 語言中的非零即真概念
在邏輯判斷時必須顯示地指明具體的判斷條件 true / false
if 語句條件的 () 可以省略
但是 {} 不能省略
let num = 100if num > 10 { print("大 \(num)") } else { print("小 \(num)") }
三目
Swift 中的 三目 運算保持了和 OC 一致的風(fēng)格
提示:以下代碼,可以按 cmd + shift + y,打開控制臺,查看輸出結(jié)果
num > 10 ? print("大 \(num)") : print("小 \(num)")
或者
num > 10 ? print("大 \(num)") : () 這樣就對后面的不作處理。 () 表示空執(zhí)行。
switch
switch 不再局限于整數(shù)
switch 可以針對任意數(shù)據(jù)類型進(jìn)行判斷
每一個 case 后面必須有可以執(zhí)行的語句
不再強制需要 break
如果沒有任何需要執(zhí)行的語句,可以使用 break
要保證處理所有可能的情況,不然編譯器直接報錯,不處理的條件可以放在 default 分支中每一個 case 中定義的變量僅在當(dāng)前 case 中有效,而 OC 中需要使用 {}
多值 case 可以使用 , 分隔
let scoreString = "優(yōu)"switch scoreString {case "優(yōu)": let name = "學(xué)生" print(name + "80~100分")case "良", "中": print("60~80分")case "差": print("不及格")default: break}
switch 的條件判斷
switch 中可以使用 where 子句判斷條件
如果只做條件判斷,case 部分可以使用 _ 省略
提示:Swift 中可以使用 _ 忽略任何不關(guān)心的內(nèi)容
let score = 90switch score {case _ where score >= 80: print("優(yōu)")case _ where score >= 70: print("良")case _ where score >= 60: print("中")default: print("差") }
for
swift取消了i++和++i和傳統(tǒng)的for循環(huán)
for i in 0...5 { }for i in 0..<5 { }
反序遍歷
for i in (0..<10).reversed() { }
三、可選項(Optional)
簡要
(1)定義變量時,如果是可選的,表示可以有值,也可以是nil,用“?”
(2)強行解包 “!”,程序員來注意!,并且要少用,可能會崩
(3)最常見的錯誤:解包的時候發(fā)現(xiàn)nil。fatal error: unexpectedly found nil while unwrapping an Optional value
(4)let可選的話,沒有默認(rèn)值,需要賦值。var可選的話,默認(rèn)值為nil
(5)可選項在參與計算時候必須解包
概念
Optional 是 Swift 的一大特色,也是 Swift 初學(xué)者最容易困惑的問題
定義變量時,在類型后面添加一個 ?,表示該變量是可選的
定義變量時,如果指定是可選的,表示該變量:
可以有一個指定類型的值
也可以是 nil
定義
格式1(自動推導(dǎo)):var 變量名: Optional = 值
格式2(泛型):var 變量名:Optional<類型> = 值
格式3(簡化格式):var 變量名: 類型? = 值
// 格式1let x: Optional = 20// 格式2let y: Optional<Int> = 30// 格式3let z: Int? = 10print(x)print(y)print(z)
默認(rèn)值
變量可選項的默認(rèn)值是 nil
常量可選項沒有默認(rèn)值,需要在定義時,或者構(gòu)造函數(shù)中賦值
var x1: Int?print(x1)let x2: Int?// 常量可選項沒有默認(rèn)值,在賦值之前不能使用// print(x2)x2 = 100print(x2)
計算和強行解包
可選值在參與計算前,必須解包 unwarping
只有解包(unwrap)后才能參與計算
在可選項后添加一個 !,表示強行解包
如果有值,會取值,然后參與后續(xù)計算
如果為 nil,強行解包會導(dǎo)致崩潰
print(x! + y! + z!)
程序員要對每一個 ! 負(fù)責(zé)
可選解包
如果只是調(diào)用可選項的函數(shù),而不需要參與計算,可以使用可選解包
在可選項后,使用 ? 然后再調(diào)用函數(shù)
使用可選解包可以:
如果有值,會取值,然后執(zhí)行后續(xù)函數(shù)
如果為 nil,不會執(zhí)行任何函數(shù)
var optionValue: Int?print(optionValue?.description)// 輸出 niloptionValue = 10print(optionValue?.description)// 輸出 Optional("10")
與強行解包對比,可選解包更安全,但是只能用于函數(shù)調(diào)用,而不能用于計算
可選項判斷
不強行解包的方法
由于可選項的值可能為 nil,不允許直接參與運算,因此在實際開發(fā)中,經(jīng)常需要判斷可選項是否有值。
如果單純使用 if,會讓代碼嵌套層次很深,不宜閱讀和維護(hù),為了解決這一問題,蘋果提供了以下三種方式:
??
if let / var
guard let / var
??
?? 運算符可以用于判斷可選項是否為 nil,如果是則使用后面的值替代
注意:?? 的優(yōu)先級低,在使用時,應(yīng)該注意使用 ()
let x: Int? = 10let y: Int? = 100print((x ?? 0) + (y ?? 0))
if let / var
使用 if let,一旦進(jìn)入 if 分支,表示可選項一定有值
常量/變量的作用域僅在 {} 內(nèi)部
使用 , 可以判斷多個可選項是否有值
使用同名常量/變量,避免再次起名的煩惱
如果要在分支邏輯中修改值,可以使用 var,通常使用 let
let name: String? = "Mike"let age: Int? = 18if let name = name, let age = age { print("\(name) 今年 \(age) 歲") } else { print("姓名或者年齡為 nil") }
guard let / var
guard 是與 if let 相反的語法,Swift 2.0 推出
guard 同樣可以判斷可選項是否有值
多值判斷使用 , 分隔
如果發(fā)現(xiàn) nil,在 else 分支返回
分支結(jié)束后,所有的 常量/變量 都有值
相比較 if let,guard 語法的分支結(jié)構(gòu)能節(jié)省一層
如果要在后續(xù)邏輯中修改值,可以使用 var,通常使用 let
func demo(name: String?, age: Int?) { guard let name = name, let age = age else { print("姓名或者年齡為 nil") return } print("\(name) 今年 \(age) 歲") } demo(name: name, age: age)
guard let和if let可以用同名變量接收。
因為總會取名字,if let name = name這樣就可以,注意后面使用的時候用非空的那個!并且iflet和guardlet可以依次判斷,先判斷是一個字典,再拿字典的數(shù)組,在判斷數(shù)組的值,可以一條線判斷出來。
四、字符串
用String,是一個結(jié)構(gòu)體,具有絕大多數(shù)NSString功能,支持直接遍歷
(1)遍歷:
func demo3() { // 字符串遍歷(NSString不支持這么遍歷) let str = "wowosnshi是" for s in str.characters { print(s) } }
(2)長度:
// 返回指定編碼對應(yīng)的字節(jié)數(shù),每個漢字三個字節(jié)print(str.lengthOfBytes(using: .utf8))// 返回真正字符串長度print(str.characters.count)
(3)拼接:要注意可選項拼接不解決會帶上Optional,剩下的都可以拼接,再也不用看StringWithFormat了
let name = "AA"let age = 19let title : String? = "sss"print("\(name)\(age)\(title ?? "")")
(4)格式化:
格式化成日期
let h = 8 , m = 10, s = 44// OC中用stringWithFormat格式化日期,Swift中可以 let strDate = String(format: "%02d-%02d-%02d", h,m,s)print(strDate)
(5)截取字符串:建議用NSStrin作中轉(zhuǎn),因為swift取串方法一直在改變
NSString方法
let str = "紅紅火火恍恍惚惚"let strOC = str as NSString strOC .substring(to: 1) strOC.substring(with: NSMakeRange(0, 2))
五、數(shù)組
(1)就是中括號,注意數(shù)組的類型,并且基本數(shù)據(jù)類型不需要包裝,可以直接方數(shù)組里,如果類型不一樣(混合數(shù)組,但是基本不用),自動推導(dǎo)[NSObject]。在Swift中還有一個[AnyObject類型],標(biāo)示任意對象,因為在Swift中一個類可以沒有任何父類。
(2)遍歷:
// 遍歷1(按照下標(biāo)遍歷) for i in 0..<array.count { } // 遍歷2(遍歷元素) for s in array { } // 遍歷3(同時遍歷下標(biāo)和元素) for e in array.enumerated() { // let e: (offset: Int, element: String) e是一個元組 print("\(e.offset), \(e.element)") } // 遍歷4(同時遍歷下標(biāo)和元素) for (n,s) in array.enumerated() { print("\(n),\(s)") } // 反序遍歷 for s in array.reversed() { } // 反序索引下標(biāo)(這樣寫才對,先枚舉再反序) for (n,s) in array.enumerated().reversed() { }
(3)增刪改:
array.append("AA") array[1] = "BBB" array.remove(at: 2)
(4)合并:用“+”號。但是要合并的數(shù)組的兩個類型必須一致。
六、字典
一般是[String:NSObject],對應(yīng)鍵值對.由于3.0后大部分都是結(jié)構(gòu)體了,AnyObject不好用了,Any范圍更大
(1)字典數(shù)組:
(2)增刪改:和數(shù)組都類似,就是兩個字典合并不像數(shù)組直接相加,而是需要遍歷
七、函數(shù)
(1)外部參數(shù),當(dāng)外部參數(shù)用_替代的時候,會在外部調(diào)用的時候忽略形參名
(2)函數(shù)的默認(rèn)值(OC不具備),這個使Swift比OC靈活很多很多,一個方法可以做很多事,因為OC會有各種參數(shù)和組合,Swift只需寫一個最多的參數(shù),然后不需要的設(shè)定默認(rèn)值就是了
(3)無返回值 :直接省略 () Void都可以
(4)閉包:類似Block,比Block還廣泛。OC中Block是匿名函數(shù),Swift中函數(shù)是特殊的閉包。閉包在整個開發(fā)中和Block的應(yīng)用場景一樣。用于控制器/自定義視圖/異步執(zhí)行完成的回調(diào)。這些回調(diào)的特點就是都是以參數(shù)回調(diào)處理結(jié)果,返回值為Void。
定義:
let biBao = { (x: Int) -> Int in return x + 100 } print(biBao(10))
GCD:將任務(wù)添加到隊列,指定執(zhí)行任務(wù)的函數(shù)。任務(wù)就是Block/閉包,隊列以同步/異步的方式執(zhí)行。
func loadData(compeletion:@escaping ( _ result: [String])->()) -> Void { DispatchQueue.global().async { print("耗時操作會獲得一些結(jié)果 \(Thread.current)") Thread.sleep(forTimeInterval: 1.0) let json = ["天氣","不錯","刮大風(fēng)"] // 主線程回調(diào) DispatchQueue.main.async(execute: { print("主線程更新UI \(Thread.current)") // 回調(diào) -> 通過參數(shù)傳遞 執(zhí)行閉包 compeletion(json) }) } }
調(diào)用:
// 執(zhí)行的適合我就拿到了值 loadData { (result) in print("獲取的新聞數(shù)據(jù) \(result)") }
尾隨閉包:如果函數(shù)的最后一個參數(shù)是閉包,那么參數(shù)就省略了,最后一個參數(shù)直接{}大括號包裝
閉包的循環(huán)引用:
(5)面向?qū)ο螅ǜ鞣N構(gòu)造函數(shù)):()就是allocInit,在Swift中對應(yīng)init()。在swift中一個項目所有類都是共享的,可以直接訪問,每一個類都默認(rèn)有一個命名空間。A.name B.name God.name Dog.name。同一個類可以從屬于不同的命名空間(假如有一個框架有Person類,做用戶,還有一個框架做后臺,也用Person。在OC中就只能靠前綴解決,HouTaiPerson,KuangJiaPerson。而Swift中的命名空間就是項目名。AAA項目有一個Person,那么AAA.Person就是AAA的Person類,此時再導(dǎo)入框架,那也是框架的.Person)
在自定義的Nsobjiect類中,has no initalizers 標(biāo)示沒有初始化器,初始化器可以有多個,默認(rèn)是init。當(dāng)這個類有屬性的時候,屬性要分配內(nèi)存空間,就是說要有初始值。那么其實就是先給自己的屬性分配,然后給父初始。其實這么一看,Swift和OC是相反的!
思路:OC是先調(diào)用爸爸。就是Person,Person會再調(diào)用NSObject,就是先跑上去什么都不管,先初始化了NSObject,然后才往下走挨個初始化。Swift是把自己完全初始化,再上去初始化爸爸,這么看比OC快了一圈,性能要好。
重載構(gòu)造函數(shù):(重寫是父類有這個方法,override。重載是函數(shù)名相同,參數(shù)和個數(shù)不同。init就重寫,init+參數(shù)就重載。OC是沒有重載的!都是initWithXXXXX)。重載其實是最基本的方式,OC沒有其實很low,但是Swift有。
注意:如果重載了構(gòu)造函數(shù)并且沒有實現(xiàn)父類的init,那么系統(tǒng)不再提供init構(gòu)造函數(shù)了(默認(rèn)是有的),因為默認(rèn)的構(gòu)造函數(shù)不能給本類的屬性分配空間(你不自己寫name = ,系統(tǒng)就沒辦法分配)
KVC構(gòu)造函數(shù):只需記住下面4點
所以一般在模型中加個? 然后用KVC實現(xiàn)(先調(diào)用init因為是運行時機制)模型中屬性定義:基本數(shù)據(jù)類型 = 0,對象設(shè)置?
運行時中,基本類型設(shè)置? 屬性設(shè)置私有都會讓運行時拿不到,此時kvc就會出錯。如果子類沒有重寫父類方法,調(diào)用的時候就會直接調(diào)用父類的方法。當(dāng)繼承一個類,就繼承所有屬性和方法,包括KVC。當(dāng)PERSON寫好了KVC后,
整體
(6)便利構(gòu)造函數(shù):關(guān)鍵字Convenience(開發(fā)用的很少,因為模型都是框架轉(zhuǎn),UI不需要便利)
*目的:條件判斷,只有滿足條件才實例化對象,防止不必要的內(nèi)存開銷,簡化對象創(chuàng)建。本身是不負(fù)責(zé)屬性的創(chuàng)建和初始化的。
(7)deinit:類似OC的Dealloc
八、分類:extension
便利構(gòu)造函數(shù) + 分類可以省略抽取很多代碼。例如給UITextField/UIButton寫分類,然后寫便利構(gòu)造函數(shù),方便。
九、Swift的類,結(jié)構(gòu)體,枚舉三種都有構(gòu)造函數(shù),都可以有方法,就像OC的類
十、其它
懶加載:
在OC開發(fā)中,懶加載一般自定義控件。在Swift中,懶加載還是需要用的,可以保證控件延遲創(chuàng)建,還能避免處理控件解包。如果直接定義控件var label = UILabel,根據(jù)代碼從上到下,會讓控件在ViewDidLad之前就提前創(chuàng)建了。所以需要懶加載。OC中懶加載就是Get方法,Swift直接lazy var。當(dāng)然也可以private lazy var來限定作用域。
(1)簡單的懶加載:
(2)完整的懶加載:()就是函數(shù)執(zhí)行,就是一個特殊的閉包,所以懶加載本質(zhì)是一個閉包。一般不這么寫。
(3)OC和Swift區(qū)別
OC:
- (UILabel *)label{ //如果label等于nil就會創(chuàng)建! if (_label == nil) { _label = [[UILabel alloc]init]; _label.text = @"loirou"; [_label sizeToFit]; _label.center = self.view.center; } return _label; }
OC是等于nil時候就懶加載
[self.view addSubview:self.label]; //釋放label _label = nil; //會再次調(diào)用懶加載的代碼 NSLog(@"%@",self.label);
當(dāng)label設(shè)nil的時候就在此調(diào)用。在ios6中,didReceiveMemoryWarning是不清理視圖的。
Swift:
此時釋放的時候就會報錯。因為定義的時候沒有?,就是一定有值得。
那么如果定義時候加? 一旦label = nil,也不會在執(zhí)行懶加載了!因為懶加載根本沒寫如果是空就創(chuàng)建。
懶加載只會在第一次調(diào)用的時候執(zhí)行閉包。Swift中一定注意不要主動清理視圖或控件,因為懶加載不會創(chuàng)建了(例如內(nèi)存警告別干掉控件,干掉了在也用不成了,因為懶加載就一次)
計算型屬性(只讀):
(1)getter/setter(開發(fā)不用):
// 開發(fā)一般不用,還給搞一個_name。 // swift一般不會重寫getter和setter private var _name: String? // 假裝的一個值 var name: String? { get{return _name} set{_name = newValue}} // get返回成員變量 set記錄成員變量 override func viewDidLoad() {
作者:洛洛愛吃肉 出處:http://www.cnblogs.com/dongliu/ 本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。 如果文中有什么錯誤,歡迎指出。以免更多的人被誤導(dǎo)。
http://www.cnblogs.com/dongliu/p/7087231.html