無(wú)意間看到自己以前學(xué)習(xí)swift的筆記,從近兩年蘋(píng)果的發(fā)布會(huì),可以看出蘋(píng)果推動(dòng)swift的決心,OC更換為swift也是未來(lái)發(fā)展的趨勢(shì),想起當(dāng)初自己鉆研學(xué)習(xí)swift的痛苦的情景,現(xiàn)在把它們整理出來(lái)并與現(xiàn)在最新的swift結(jié)合以供初學(xué)者使用,讓初學(xué)者少走彎路。有時(shí)間會(huì)陸續(xù)整理后面知識(shí)的學(xué)習(xí)筆記。
第一個(gè) swift 項(xiàng)目
新建 swift 項(xiàng)目步驟和 oc 相同,只需要在建項(xiàng)目時(shí),選擇編程語(yǔ)言為 swift
打開(kāi) ViewController.swift 文件,鍵入以下代碼,點(diǎn)擊運(yùn)行,執(zhí)行我們的第一個(gè)單頁(yè)面的 swift 項(xiàng)目。
//
import UIKit
//類的聲明和實(shí)現(xiàn),寫(xiě)在一個(gè) .swift 文件里面
//用點(diǎn)語(yǔ)法替代了 oc 的 []語(yǔ)法
//對(duì)變量常量的定義取消了指針
//swfit 可以直接調(diào)用的 oc 的 Foundation 框架和 UIKit 框架的 api
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//相當(dāng)于 oc 的 [[UIView alloc] initWithFrame: CGRectMake(0, 20, 200, 200)]
let subView = UIView(frame: CGRect(x: 0, y: 20, width: 200, height: 200))
subView.backgroundColor = UIColor.blueColor()
view.addSubview(subView)
let button = UIButton(type: .Custom)
button.frame = CGRect(x: 10, y: 10, width: 50, height: 30)
button.backgroundColor = UIColor.purpleColor()
subView.addSubview(button)
button.addTarget(self, action: "buttonClick", forControlEvents: UIControlEvents.TouchUpInside)
}
func buttonClick() {
print("hello, world!")
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
總結(jié)
- 在 Swift 中沒(méi)有了 main.m,@UIApplicationMain 是程序入口
- 在 Swift 中只有 .swift 文件,沒(méi)有 .h/.m 文件的區(qū)分
- 在 Swift 中,一個(gè)類就是用一對(duì) {} 括起的,沒(méi)有 @implementation 和 @end
- 每個(gè)語(yǔ)句的末尾沒(méi)有分號(hào),在其他語(yǔ)言中,分號(hào)是用來(lái)區(qū)分不同語(yǔ)句的
- 在 Swift 中,一般都是一行一句代碼,因此不用使用分號(hào)
與 OC 的語(yǔ)法快速對(duì)比
- 在 OC 中 alloc / init 對(duì)應(yīng) ()
- 在 OC 中 alloc / initWithXXX 對(duì)應(yīng) (XXX: )
- 在 OC 中的類函數(shù)調(diào)用,在 Swift 中,直接使用 .
- 在 Swift 中,絕大多數(shù)可以省略 self.,建議一般不寫(xiě),可以提高對(duì)語(yǔ)境的理解(閉包時(shí)會(huì)體會(huì)到)
- Swift 中,枚舉類型的前綴可以省略,如:.ContactAdd,但是:很多時(shí)候沒(méi)有智能提示
- 監(jiān)聽(tīng)方法,直接使用字符串引起
- 在 Swift 中使用 print() 替代 OC 中的 NSLog,效率更高!
playGround 介紹
- playGround 是 xcode6.0 之后推出的一個(gè)新功能,可以一邊寫(xiě) swfit 代碼,一邊即時(shí)結(jié)果,無(wú)需手動(dòng)編譯;
- playGround 是一款不錯(cuò)的 swfit 學(xué)習(xí)工具,如果開(kāi)發(fā)項(xiàng)目,仍然需要新建項(xiàng)目。
- 由于playGround是即時(shí)編譯,所以容易報(bào)錯(cuò)(電腦配置過(guò)低也容易報(bào)錯(cuò)),如果確認(rèn)語(yǔ)法沒(méi)錯(cuò) ,需要重行啟動(dòng)playGround
基本語(yǔ)法
常量和變量
定義
- let 定義常量,一經(jīng)賦值不允許再修改
- var 定義變量,賦值之后仍然可以修改
// 定義常量 let / 變量 var
// 格式: let/var 變量名: 類型 = 值
// 提示: Swift 提供了自動(dòng)推導(dǎo),如果使用默認(rèn)的數(shù)據(jù)類型,: 數(shù)據(jù)類型
可以省略
// 格式: let/var 變量名 = 值,變量類型會(huì)根據(jù)右側(cè)的結(jié)果自動(dòng)推導(dǎo)
// 定義常量并且直接設(shè)置數(shù)值
let x: Int = 10
// 常量數(shù)值一經(jīng)設(shè)置,不能修改,以下代碼會(huì)報(bào)錯(cuò)
// x = 30
// 使用 : 類型
,僅僅只定義類型,而沒(méi)有設(shè)置數(shù)值
let y: Int
// 常量有一次設(shè)置數(shù)值的機(jī)會(huì),以下代碼沒(méi)有問(wèn)題,因?yàn)?y
還沒(méi)有被設(shè)置數(shù)值
y = 10
// 一旦設(shè)置了數(shù)值之后,則不能再次修改,以下代碼會(huì)報(bào)錯(cuò),因?yàn)?y
已經(jīng)被設(shè)置了數(shù)值
// y = 50
print(x + y)
// 變量設(shè)置數(shù)值之后,可以繼續(xù)修改數(shù)值
var z: Int
z = 100
z = 200
print(x + y + z)
類型自動(dòng)推導(dǎo)
Swift能夠根據(jù)右邊的代碼,推導(dǎo)出變量的準(zhǔn)確類型
通常在開(kāi)發(fā)時(shí),不強(qiáng)制要求指定變量的類型,如果需要指定,可以在變量名后使用:,然后跟上變量的類型
重要技巧:Option + Click 可以查看變量的類型
沒(méi)有隱式轉(zhuǎn)換
Swift 對(duì)數(shù)據(jù)類型要求異常嚴(yán)格。在任何時(shí)候,都不會(huì)做隱式轉(zhuǎn)換,如果要對(duì)不同類型的數(shù)據(jù)進(jìn)行計(jì)算,必須要顯式的轉(zhuǎn)換。
let x = 100 //swfit 會(huì)自動(dòng)推導(dǎo) x 為整型
let y = 10.5 //swfit 會(huì)自動(dòng)推導(dǎo) y 為浮點(diǎn)型
let num = Double(x) + y
let num1 = x + Int(y)
let 和 var 的選擇
應(yīng)該盡量先選擇常量,只有在必須修改時(shí),才需要修改為 var
- 在 Xcode 7.0 中,如果沒(méi)有修改變量,Xcode 會(huì)提示修改為 let
可選值
可選值(Optional) 是 Swift 的一大特色,也是 Swift 初學(xué)者最容易困惑(痛不欲生)的問(wèn)題
所謂可選值(optional),就是指一個(gè)變量或常量,可能有值,也可能沒(méi)有值。
場(chǎng)景舉例:用一個(gè)值保存網(wǎng)絡(luò)請(qǐng)求的數(shù)據(jù);如果請(qǐng)求成功,則有值;如果請(qǐng)求失敗,就沒(méi)有值。
可選值的定義
定義常量/變量時(shí),在類型后面加一個(gè)?表示該變量是可選的。
可選值必須提定類型
定義一個(gè)可選變量時(shí),表示該變量可以有一個(gè)指定類型的值,也可以是 nil;變量可選項(xiàng)的默認(rèn)值是 nil
常量可選項(xiàng)沒(méi)有默認(rèn)值,主要用于在構(gòu)造函數(shù)中給常量設(shè)置初始數(shù)值
let x: Optional = 10
let y: Optional<Int>
let a: Int? //a默認(rèn)沒(méi)有值
var b: String? //b的默認(rèn)值為 nil
let aa: Int? = 10 //aa
let bb: String? = "hello, world"
- 可選值解包
如果 Optional 值是 nil,不允許參與計(jì)算, 只有解包(unwrap)后才能參與計(jì)算
?告訴編譯器:我是一個(gè)可選值,不要拿我做運(yùn)算
!告訴編譯器:我一定有值,快來(lái)使用我吧!一旦編譯器解包后發(fā)現(xiàn)沒(méi)有值,就會(huì)崩潰(比如說(shuō)你女朋友過(guò)生日,你送給她一個(gè)iPhone10的盒子,她興奮的打開(kāi),發(fā)現(xiàn)里面是空的,那就會(huì)生氣發(fā)火)
如果不確定可選值是否有值,使用前,需要判斷是否為nil
注意:必須要確保解包后的值不是 nil,否則會(huì)報(bào)錯(cuò)
- 常見(jiàn)錯(cuò)誤
unexpectedly found nil while unwrapping an Optional value 翻譯 在對(duì)可選項(xiàng)[解包]時(shí)發(fā)現(xiàn) nil
可選綁定
由于可選項(xiàng)的內(nèi)容可能為 nil,而一旦為 nil 則不允許參與計(jì)算。因此在實(shí)際開(kāi)發(fā)中,經(jīng)常需要判斷可選項(xiàng)的內(nèi)容是否為 nil
單個(gè)可選項(xiàng)判斷
let url = NSURL(string: "http://www.baidu.com")
//: 方法1: 強(qiáng)行解包 - 缺陷,如果 url 為空,運(yùn)行時(shí)會(huì)崩潰
let request = NSURLRequest(URL: url!)
//: 方法2: 首先判斷 - 代碼中仍然需要使用 !
強(qiáng)行解包
if url != nil {
let request = NSURLRequest(URL: url!)
}
//: 方法3: 使用 if let
,這種方式,表明一旦進(jìn)入 if 分支,u 就不在是可選項(xiàng)
if let u = url where u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
可選項(xiàng)條件判斷
//: 1> 初學(xué) swift 一不小心就會(huì)讓 if 的嵌套層次很深,讓代碼變得很丑陋
if let u = url {
if u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
}
>//: 2> 使用 where 關(guān)鍵字,
if let u = url where u.host == "www.baidu.com" {
let request = NSURLRequest(URL: u)
}
小結(jié): if let 不能與使用 &&、|| 等條件判斷 如果要增加條件,可以使用 where 子句 注意:where 子句沒(méi)有智能提示
多個(gè)可選項(xiàng)判斷
- 可以使用
,
同時(shí)判斷多個(gè)可選項(xiàng)是否為空
let oName: String? = "張三"
let oNo: Int? = 100
if let name = oName {
if let no = oNo {
print("姓名:" + name + " 學(xué)號(hào): " + String(no))
}
}
if let name = oName, let no = oNo {
print("姓名:" + name + " 學(xué)號(hào): " + String(no))
}
判斷之后對(duì)變量需要修改
let oName: String? = "張三"
let oNum: Int? = 18
if var name = oName, num = oNum {
name = "李四"
num = 1
print(name, num)
}
guard
guard 是與 if let 相反的語(yǔ)法,Swift 2.0 推出的
let oName: String? = "張三"
let oNum: Int? = 18
guard let name = oName else {
print("name 為空")
return
}
guard let num = oNum else {
print("num 為空")
return
}
// 代碼執(zhí)行至此,name & num 都是有值的
print(name)
print(num)
在程序編寫(xiě)時(shí),條件檢測(cè)之后的代碼相對(duì)是比較復(fù)雜的,在判斷的層次比較多的時(shí)候,使用 guard,減少嵌套的層次
if條件判斷
Swift 中沒(méi)有 C 語(yǔ)言中的非零即真概念
在邏輯判斷時(shí)必須顯示地指明具體的判斷條件 true / false
if 語(yǔ)句條件的 () 可以省略
但是 {} 不能省略
let num = 200
if num < 10 {
print("比 10 小")
} else if num > 100 {
print("比 100 大")
} else {
print("10 ~ 100 之間的數(shù)字")
}
三目運(yùn)算
Swift 中的 三目 運(yùn)算保持了和 OC 一致的風(fēng)格
x > 20 ? print("大了") : print("小了")
/**
'( )' 表示執(zhí)行
*/
x > 20 ? print("真的大了") : ()
適當(dāng)?shù)剡\(yùn)用三目,能夠讓代碼寫(xiě)得更加簡(jiǎn)潔
判斷可選值是否為 nil
讓變量/常量強(qiáng)行解包參與運(yùn)算會(huì)有風(fēng)險(xiǎn),如果沒(méi)有值,則會(huì)崩潰,所以在使用可選值時(shí),最好先判斷 可選值是否為 nil
var a: Int? = 10
var b = 10
if a != nil {
print("有值為\(a!+b)")
}else{
print("沒(méi)有值")
}
?? 空合運(yùn)算符
?? 運(yùn)算符可以用于判斷 變量/常量 的數(shù)值是否是 nil,如果是則使用后面的值替代
在使用 Swift 開(kāi)發(fā)時(shí),?? 能夠簡(jiǎn)化代碼的編寫(xiě)
var a: Int? = 10
var b = 10
if (a ! = nil) {
a = 0
}
let c = a + b
let d = (a ?? 0) + b
//注意:?? 的優(yōu)先級(jí)低,在使用時(shí),應(yīng)該注意使用 ()
var str: String? = "小明"
// 注意 `??` 的優(yōu)先級(jí)低,在使用時(shí),應(yīng)該注意使用 `()`
print((str ?? "無(wú)名") + " 你好")
print(str ?? "無(wú)名" + " 你好")
switch
switch 不再局限于整數(shù)
switch 可以針對(duì)任意數(shù)據(jù)類型進(jìn)行判斷
不再需要 break
每一個(gè) case后面必須有可以執(zhí)行的語(yǔ)句
要保證處理所有可能的情況,不然編譯器直接報(bào)錯(cuò),不處理的條件可以放在 default 分支中
每一個(gè) case 中定義的變量?jī)H在當(dāng)前 case 中有效,而 OC 中需要使用 {}
let score = "優(yōu)"
switch score {
case "優(yōu)":
let name = "學(xué)生"
print(name + "80~100分")
case "良": print("70~80分")
case "中": print("60~70分")
case "差": print("不及格")
default: break
}
- 也可以作條件判斷
var score = 80
switch score {
case let x where x < 60:
print("不及格")
case let x where x >= 60 && x < 70:
print("及格")
case let x where x >= 70 && x < 80:
print("良好")
case let x where x >= 80 && x < 90:
print("優(yōu)秀")
case let x where x >= 90 && x <= 100:
print("牛逼")
default:
print("超過(guò)數(shù)值")
}
- 注意
如果條件沒(méi)有覆蓋所有的值,需要加default
for 循環(huán)
OC 風(fēng)格的循環(huán)
var sum = 0
for var i = 0; i < 10; i++ {
sum += i
}
print(sum)
swift 風(fēng)格的循環(huán)
- 0...10表示閉區(qū)間,數(shù)學(xué)中的[0,10]
- 0..<10表示開(kāi)區(qū)間[0,10)
var sum = 0
//for-in,0..<10, 表示從0到9
for i in 0..<10 {
sum += i
}
for j in (0..10).reverse() {
print(j)
}
print(sum)
//范圍 0...10 表示從0到10
sum = 0
for i in 0...10 {
sum += i
}
print(sum)
注意:..< 和 ... 用于定義 Range 類型,左右都不要添加空格
格式: for 變量 in 范圍 { // 代碼 }
省略下標(biāo),符號(hào) '_'
for _ in 0...10 {
print("hello")
}