Swift開發(fā)語法

Swift開發(fā)入門


簡介

  • Swift 語言由蘋果公司在 2014 年推出,用來撰寫 OS X 和 iOS 應(yīng)用程序
  • 2014 年,在 Apple WWDC 發(fā)布

歷史

  • 2010 年 7 月,蘋果開發(fā)者工具部門總監(jiān) Chris Lattner(克里斯·拉特納) 開始著手 Swift 編程語言的設(shè)計工作
  • 用一年時間,完成基本架構(gòu)
  • Swift 大約歷經(jīng) 4 年的開發(fā)期,2014 年 6 月發(fā)表


    克里斯·拉特納

    )

特色

  • 蘋果宣稱 Swift 的特點是:快速、現(xiàn)代、安全、互動,而且明顯優(yōu)于 Objective-C 語言
  • 可以使用現(xiàn)有的 CocoaCocoa Touch 框架
  • Swift 取消了 Objective C 的指針及其他不安全訪問的使用
  • 舍棄 Objective C 早期應(yīng)用 Smalltalk 的語法,全面改為句點表示法
  • 提供了類似 Java 的名字空間(namespace)、泛型(generic)、運算對象重載(operator overloading)
  • Swift 被簡單的形容為 “沒有 C 的 Objective-C”(Objective-C without the C)

現(xiàn)狀

  • 2015 年 2 月,蘋果同時推出 Xcode 6.2 Beta 5 和 6.3 Beta,在完善 Swift 1.1的同時,推出了 Swift 1.2 測試版
  • 2015 年 6 月,蘋果在 WWDC 發(fā)布了 Swift 2.0 測試版,并且宣稱在年底開源
  • 從發(fā)布至今,蘋果的每一個舉措都彰顯其大力推廣 Swift 的決心
  • Swift 當(dāng)前正式版本:1.2,測試版本是 2.0
  • 目前有些公司的新項目已經(jīng)直接采用 Swift 開發(fā)
  • 目前很多公司已經(jīng)在做 Swift 的人才儲備
  • 應(yīng)聘時,會 Swift 開發(fā) 無疑會增加自身籌碼
  • 到 2015 年底,iOS 9.0 正式發(fā)布的同時,Swift 勢必大行其道!

資源網(wǎng)站

  • 1.開發(fā)入門
    • 簡單體驗
var i = 10
print(i)
i = 15
print(i)

let j = 20
// 常量一經(jīng)定義不能自改數(shù)值
//        j = 25
print(j)
  • 創(chuàng)建對象
  • 從OC轉(zhuǎn)換為Swift的規(guī)律: alloc initXXX --> (xxxx:)
OC: [[UIView alloc] init] -- [[UIView alloc] initWithFrame:]
Swift: UIView() -- UIView(frame: )
  • 分號
    • 在OC中每一條語句后面必須跟上一個;, Swift中如果一行只有一條語句, 那么;可以省略
  • 調(diào)用方法
OC: [UIColor redColor];
Swift: UIColor.redColor()
  • 枚舉
OC: UIButtonTypeContactAdd
Swift: UIButtonType.ContactAdd
  • 示例
// 1.創(chuàng)建UIView
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
customView.backgroundColor = UIColor.redColor()
// 2.創(chuàng)建一個按鈕
let btn = UIButton(type: .ContactAdd)
btn.center = CGPoint(x: 50, y: 50)
// 3.將按鈕添加到UIView上
customView.addSubview(btn)

  • 2.常量和變量
// 定義變量
var i = 10
print(i)
i = 15
print(i)

let j = 20
// 常量一經(jīng)定義不能自改數(shù)值
//        j = 25
print(j)
  • 小結(jié)
    • var 定義變量,設(shè)置之后可以修改
    • let 定義常量,設(shè)置之后不可以修改
    • 語句末尾不用使用 ;
    • 在 Swift 中使用 print() 替代 OC 中的 NSLog
    • print 的性能更好
  • 定義 OC 對象
// 實例化視圖
let v = UIView(frame: CGRectMake(0, 0, 100, 100))
// 設(shè)置背景顏色
v.backgroundColor = UIColor.redColor()

// 添加到根視圖
view.addSubview(v)
  • 小結(jié)
    • Swift 中要實例化一個對象可以使用 類名() 的格式,與 OC 中的 alloc/init 等價
    • OC 中的 initWithXXXSwift 中通常可以使用 類名(XXX: ) 找到對應(yīng)的函數(shù)
    • OC 中的 [UIColor redColor] 類方法,在 Swift 中通常可以使用 類名.XXX 找到對應(yīng)的函數(shù)
    • 使用 let 修飾 v 并且賦值,表示 該常量的內(nèi)存地址不允許修改,但是可以修改其內(nèi)部的屬性
    • 當(dāng)前對象的屬性,不需要使用 self.

常量&變量的使用原則:盡量先用 let,只有需要變的時候,再用 var,能夠更加安全

  • 變量類型
let x = 10
let y = 10.5
let z: Double = 20

print(Double(x) + y) // 20.5
print(x + Int(y)) // 20
print(y + z) // 30.5
  • 小結(jié)
    • 初次接觸 Swift 中會因為簡單的 var let 誤以為 Swift 中的類型非常松散
    • 其實所有變量的準(zhǔn)確類型都是在賦值的同時自動推導(dǎo)的
    • Swift 是對類型要求非常嚴(yán)格的一門語言,一個值永遠(yuǎn)不會被自動轉(zhuǎn)換成其他類型
    • 如果要轉(zhuǎn)換,必須顯示轉(zhuǎn)換,Swift 中
      • 小數(shù)默認(rèn)是 Double 類型
      • 整數(shù)默認(rèn)是 Int 類型
    • 如果要顯式的指定變量的類型,可以在定義是使用 var 變量名: 類型 = 值
    • 變量: var
    • 常量: let
    • 格式: 修飾符 變量/常量名稱: 數(shù)據(jù)類型 = 值
  • 數(shù)據(jù)類型
    • 只要將OC中的數(shù)據(jù)類型第一個字母轉(zhuǎn)換為大寫, 就是Swift中的數(shù)據(jù)類型
  • 注意點:
    • 在Swift開發(fā)中, 一般情況下先用let, 只要需要修改數(shù)據(jù)時才用var, 使用let的好處, 可以避免數(shù)據(jù)被修改, 可以保證數(shù)據(jù)安全性
var number: Int = 30
number = 50

let number2: Int = 88
//number2 = 55
  • 類型推導(dǎo):
    • Swift中如果在定義變量/常量時進行初始化, 那么數(shù)據(jù)類型可以不用寫,系統(tǒng)會自動根據(jù)右邊的復(fù)制推導(dǎo)出變量/常量的類型
    • Swift開發(fā)中能不寫數(shù)據(jù)類型就不寫數(shù)據(jù)類型, 盡量使用編譯器的自動推導(dǎo)
    • 只有當(dāng)我們需要明確的指定數(shù)據(jù)的長度, 獲取需要先定義再初始化時才明確的指定數(shù)據(jù)類型
    • 使用自動類型推導(dǎo)好處: 大大降低代碼中的冗余代碼
let number3 = 10.10

var number4: Int
number4 = 99
  • 類型轉(zhuǎn)換:
    • OC中有顯示轉(zhuǎn)換和隱式轉(zhuǎn)換 double value = 10.1 + 9
    • Swift中只有顯示轉(zhuǎn)換沒有隱式轉(zhuǎn)換, 也就是說只有相同類型的數(shù)據(jù)才能進行賦值和計算
// 只有相同數(shù)據(jù)類型才能賦值
let number5: Int = Int(55.5) // 50

// 只有相同數(shù)據(jù)類型才能進行運算
let number6 = 10
let number7 = 88.8
let sum = Double(number6) + number7 // 98.8

// CGFloat --> double

let size = CGSize(width: 10, height: 10)
let number8 = 10.1
let sum2 = size.width + CGFloat(number8) // 20.1

  • 3.元祖
let number1 = 10
let number2 = 10.1
  • 元祖

    • 復(fù)合數(shù)據(jù)類型
    • 只要將多個相同或者不同的數(shù)據(jù)用()括起來就是元祖
    • 優(yōu)點: 在以前沒有元祖之前C和OC語言是通過傳入指針或者返回結(jié)構(gòu)體的方式來返回多個值的,而有了元祖之后就可以實現(xiàn)讓一個函數(shù)返回多個值
let number3: (Int, Double, Int, Double) = (10, 10.1, 9, 44.40) //(.0 10, .1 10.1, .2 9, .3 44.4)
number3.0 // 10
number3.1 // 10.1
number3.2 // 9
number3.3 // 44.40

// 給元祖的元素起名稱
let person = (name: "gcy", age: 30, score: 100.0) // (.0 "gcy", .1 30, .2 100)
person.name // "gcy"
person.age // 30
person.score // 100


// 提取元祖的數(shù)據(jù)
let (name, age, score) = ("gcy", 30, 100.0)
name
age
score

  • 4.分支
var i = 10

if i > 0 {
    print("OK")
}
  • 小結(jié)
    • Swift 中沒有 C 語言中的非零即真概念
    • 在邏輯判斷時必須顯示地指明具體的判斷條件
    • if 語句條件的 () 可以省略
    • 但是 {} 不能省略
  • if
    • 大部分用于和OC中一致
    • Swif中條件語句可以不用寫()
    • OC中如果if后面只有一條語句, 那么{}可以省略, 但是Swift不行
    • OC中條件語句可以是任何數(shù)值, OC中非0即真, YES/NO
    • Swift中條件語句的取值必須是Bool類型,
    • 也就是說Swift中提供了真正的Bool類型, true/false
let number = 10
//if number = 10 // Swift有效的避免了這種問題
if number == 10
{
    print(number)
}

let age = 16
if age >= 18
{
    print("開網(wǎng)卡")
}else
{
    print("回家找媽媽")
}
  • 三目運算符
var a = 10
var b = 50

var result = a > b ? a : b
print(result) // 50
  • 小結(jié)
    • Swift 中的 三目 運算保持了和 OC 一致的風(fēng)格
    • 大部分用法和OC一樣
    • 條件表達(dá)式只能是Bool值
print(age >= 18 ? "開網(wǎng)卡" : "回家找媽媽")
  • switch
    • 大部分用法和OC一樣
      Swift中條件語句可以不用寫()
    • OC中default可以省略, 而Swift中大部分情況不能省略
    • OC中default的位置可以隨便寫, 而Swift不可以
    • OC中每個case后面必須加上break, 否則會出現(xiàn)穿透, 而Swift不會穿透, 也就是說不用寫break
    • OC中要在case中間定義變量必須加上{}, 否則作用域混亂, 而Swift不用
    • 可以判斷區(qū)間和元祖

let score = 100
switch score
{
case 59:
    print("不及格")
    var num = 100
case 100:
    print("滿分")
default:
    print("Other")
}
  • 區(qū)間
    • 閉區(qū)間: 0...10 , 取值范圍0~10, 包含頭包含尾
    • 半閉區(qū)間: 0..<10 取值范圍0~9, 包含頭不包含尾
// 判斷區(qū)間
switch score
{
case 0..<60: // 0~59
    print("不及格")
case 60..<80: // 60~79
    print("良好")
case 80..<100: // 80~99
    print("優(yōu)秀")
default:
    print("滿分")
}

let point = (100, 50)
// 判斷元祖
switch point
{
case (0, 0):
    print("原點")
case (50, 50):
    print("中點")
case (100, 100):
    print("右下角")
default:
    print("Other")
}

// 取出元祖中的值
switch point
{
case (var x, var y) where x > y:
    print(x)
    print(y)
default:
    print("Other")
}

  • 5.可選類型
  • 什么是可選類型: 一個變量可以有值也可以沒有值, 我們就稱之為可選類型
    • 在Swift中如果使用一個可選類型的變量/常量, 必須解包操作
      • 解包: 只需要在變量/常量后面加上 !
      • !含義: 代表告訴系統(tǒng)該變量/常量中一定有值, 如果強制解包一個沒有值的常量/變量,那么會報錯
    • 優(yōu)點: 提高代碼閱讀性
    • 格式: 修飾符 變量名稱:Optional<數(shù)據(jù)類型> 修飾符 變量名稱: 數(shù)據(jù)類型?
    • 語法糖: 因為在Swift中可選類型用得非常非常多, 所以為了簡化代碼, Swift提供了一個語法糖, 可以用? 代替 Optional<數(shù)據(jù)類型>
  • 提示: 對于初學(xué)者來說 ? ! 是最為頭疼的語法, 剛開始的時候建議利用Xocde的語法提示來解決? !的問題
//var number: Optional<Int> = nil
//var number2: Int = nil

let number: Optional<Int> = 10
print(number!) // 10
let number2 = 10
let sum = number! + number2 // 20


let number3: Int? = 55
print(number3) // "Optional(55)\n"

/*
可選類型注意點:
* 在開發(fā)中一般情況下盡量不要強制解包一個可選類型, 否則會引發(fā)錯誤
*/

//let url = NSURL(string: "http://www.baidu.com")
//print(url)
//let request = NSURLRequest(URL: url!) // "Optional(http://www.baidu.com/)\n"

let url = NSURL(string: "http://www.baidu.com/")
print(url)
//let request = NSURLRequest(URL: url!)
if url != nil
{
    let request = NSURLRequest(URL: url!)
}

// 可選綁定: 如果url不為nil, 系統(tǒng)內(nèi)部就會自動將解包之后的值賦值給temp, 并且只有temp有值時才會執(zhí)行{}中的代碼
// Swift開發(fā)中推薦這種寫法
if let temp = url
{
    let request = NSURLRequest(URL: temp)
}
  • 演練 1
let url = NSURL(string: "http://www.baidu.com/")

if url != nil {
    NSURLSession.sharedSession().dataTaskWithURL(url!, completionHandler: { (data, _, _) -> Void in
        print(NSString(data: data!, encoding: NSUTF8StringEncoding))
    }).resume()
}
  • 小結(jié)

    • Swift 中,不是所有的對象實例化方法都會返回值,在實際開發(fā)中需要注意實例化函數(shù)的返回類型,例如:

convenience init?(string URLString: String)


    * 如果有 `?` 表示改方法有可能無法實例化到正確的對象
    * 這種函數(shù)返回的對象,被稱為 `可選項`,即有可能有值,也有可能沒有值
    * 實際開發(fā)時,需要針對這種對象加以判斷,并且在分支內(nèi)部使用 `!`,指明改對象確實是存在的
    * 相比在 `OC` 的開發(fā),尤其在日常練習(xí)時,會給定一個能夠運行的值,而在實際運行時,一旦條件不滿足,會直接閃退,這樣用戶體驗會非常不好

> `Swift` 的設(shè)計者考慮到因為對類型的強制要求,會讓代碼很難看,因此提供了一個變通的解決方案

- 演練 2

```swift
if let url = NSURL(string: "http://baidu.com") {
    NSURLSession.sharedSession().dataTaskWithURL(url, completionHandler: { (data, _, _) -> Void in
        print(NSString(data: data!, encoding: NSUTF8StringEncoding))
    }).resume()
}
  • 小結(jié)

    • 使用 if let 常量 = 可選構(gòu)造函數(shù) 的方式能夠確保分支內(nèi)部常量一定是有值的
    • 并且在分支內(nèi)部不再需要使用 !
    • 這是 Swift 代碼中的一個非常重要的使用技巧
  • 提示

    • 盡管 Swift 提供了類型校驗的手段,但是要寫出 優(yōu)雅 的 Swift 代碼,還是需要多加練習(xí)的,否則一不小心就會出現(xiàn)分支嵌套層次很深的代碼
    • 有關(guān) ?! 的選擇,可以借助 Xcode 的輔助工具,但是強烈建議每次遇到提示時,要多加思考,反復(fù)揣摩
  • 演練3
var name: String? // nil
print(name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) // "nil\n"

//name = "gcy"
print(name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding)) // "nil\n"


print((name?.lengthOfBytesUsingEncoding(NSUTF8StringEncoding) ?? 0)) //"0\n"
  • 小結(jié)
    • ?? 是一個非常有用的操作符,能夠快速對 nil 進行判斷
    • 如果對象是 nil,則使用 ?? 后面的值代替前面的 nil 值參與計算
    • 在使用 ?? 時,整個部分需要使用 () 包裝
    • 這一技巧在 UITableView 的數(shù)據(jù)源方法中尤為重要

  • 6.循環(huán)
  • OC風(fēng)格的 for
// 傳統(tǒng)寫法
for var i = 0; i < 10; i++ {
    print(i) // (10 times)
}
  • Swift風(fēng)格的 for
// 遍歷 0 ~ <10
for i in 0..<10 {
    print(i) // (10 times)
}

print("---") // "---\n"

// 遍歷 0 ~ 10
for i in 0...10 {
    print(i) // (11 times)
}
  • 小結(jié)
    • Swift 中使用 in 關(guān)鍵字標(biāo)示循環(huán)的范圍
    • 0..<10 表示從0到9
    • 0...10 表示從0到10
    • 注意之間不能出現(xiàn)空格
  • 特殊寫法
for _ in 0...10 {
    print("hello") // (11 times)
}
  • 小結(jié)

    • 如果不關(guān)心循環(huán)本身的索引,可以使用 _ 忽略
    • 傳統(tǒng)for
      • 基本用法和OC一致
      • for后面的()可以省略
      • for后面的{}不可用省略
      • Swift開發(fā)中不建議使用傳統(tǒng)for循環(huán)
for var i = 0; i < 10; i++
{
    print(i) // (10 times)
}

//死循環(huán)
for ;;
{
    print("---") // (18657 times)
}
// Swift開發(fā)中推薦的for循環(huán)格式
for i in 0..<10
{
    print(i) // (10 times)
}
  • while
    • 基本用法和OC一致
var number = 0
while number < 10
{
    print(number) // (10 times)
    number++
}
  • do while
    • 基本用法和OC一致
    • Swift2.0開始dowhile循環(huán)中沒有do, 只有repeat, 因為do被作用異常處理
var index = 0
repeat{
    print(index) // (10 times)
    index++
}while index < 10

  • 7.數(shù)組
    • 數(shù)組
      • 格式 var arr: Array<Int> / var arr: [Int]
      • 可變和不可變 var/let
  • 簡單體驗
let arr = ["zhangsan", "lisi"]
print(arr) // "["zhangsan", "lisi"]\n"

// 遍歷每一個元素
for a in arr {
    print(a) // (2 times)
}

// 像 OC 一樣打印
print(arr as NSArray) // "(\n    zhangsan,\n    lisi\n)\n"

  • 數(shù)組中保存的對象類型
// 數(shù)組中保存的都是字符串
let arr = ["zhangsan", "lisi"]

// 數(shù)組中保存的是 NSObject
let arr1 = ["zhangsan", 1]
  • 小結(jié)
    • 數(shù)組使用 [] 定義,這一點與 OC 相同
    • 如果初始化時,所有內(nèi)容類型一致,則數(shù)組中保存的是該類型的內(nèi)容
    • 如果初始化時,所有內(nèi)容類型不一致,則數(shù)組中保存的是 NSObject
  • 常見數(shù)組操作
// 定義只能保存字符串類型數(shù)組
var array: [String]

// 初始化數(shù)組
array = ["zhangsan"]

// 添加元素
array.append("lisi")

print(array) // "["zhangsan", "lisi"]\n"

// 刪除元素
array.removeAtIndex(1) // "lisi"
print(array) // "["zhangsan"]\n"

// 刪除所有元素
array.removeAll(keepCapacity: true) // []
print(array.capacity) // "2\n"

// 注意數(shù)組容量的變化
for i in 0..<10 {
    array.append("\(i)") // (10 times)
    print("\(array) --- \(array.capacity)") // (10 times)
}

// 實例化新的數(shù)組
var array2 = [String]() // []
array2.append("1") //["1"]
array2.append("2") // ["1", "2"]

// 拼接數(shù)組
array += array2 // ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "2"]

print(array) // "["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "1", "2"]\n"
  • 小結(jié)
    • 如果定義數(shù)組時指定了保存對象的類型,擇不能向數(shù)組中添加其他類型的內(nèi)容
    • 可以使用 [String]()
    • let 定義的數(shù)組是不可變的
    • var 定義的數(shù)組是可變的
// 定義數(shù)組
//var arr: Array<Int>
//var arr: [Int]
//arr = [1, 2]
var arr = [1, 2]

// 1.遍歷數(shù)組(取值)
arr[0]
for item in arr
{
    print(item) // (2 times)
}
// 2.添加
arr.append(3)
arr
// 3.修改
arr[1] = 9
arr

// 4.刪除
arr.removeAtIndex(0) // 1
arr // [9, 3]

// 5.合并
var arr1 = [3, 5, 7]
arr += arr1 // [9, 3, 3, 5, 7]
arr // [9, 3, 3, 5, 7]

// 6.Swift特殊
for item in arr[0..<2] // 0~1
{
    print(item) // (2 times)
}

//arr.removeRange(Range(start: 0, end: 2))
//arr

// 通過觀察可以發(fā)現(xiàn)Range其實就是一個半閉區(qū)間
arr.removeRange(0..<2) // [3, 5, 7]
arr // [3, 5, 7]

arr += arr1[0..<2] // [3, 5, 7, 3, 5]

  • 8.字典

    • 字典
      • 格式 var dict: Dictionary<String, String>
      • 注意: 將OC的{}換成了[]
      • 可變和不可變 var/let
//var dict: Dictionary<String, String>
//var dict: [String: String]
var dict = ["name": "gcy", "age": "30"]
dict

// 企業(yè)開發(fā)中字典使用得最多的類型就是 [String: NSObject]類型
var dict2 = ["name": "gcy", "age": 30, "score": 99.9]
dict2

// 取值
dict2["name"]

// 修改
dict2["name"] = "wy"
dict2

// 增加
// 如果key存在就直接修改, 如果key不存在就會增加
dict2["rank"] = 1
dict2

// 刪除
dict2.removeValueForKey("name")
dict2

// 遍歷
// OC寫法
for key in dict2.keys
{
    print(dict2[key]) // (3 times)
}

// Swift寫法
// 系統(tǒng)會自動將字典中的key賦值給元祖中的第一個遍歷, 會自動將字典中的value賦值給元祖中的第二個遍歷
for (xx, oo) in dict2
{
    print(xx) // (3 times)
    print(oo) // (3 times)
}

// 合并
var dict3 = ["name": "gcy", "age": 30]
var dict4 = ["score": 99.9]

// 注意點無論是數(shù)組還是字典, 只有相同類型才能賦值
for (key, value) in dict4
{
    dict3[key] = value // 99.9
}
dict3 // ["score": 99.9, "age": 30, "name": "gcy"]

  • 9.字符串

在 Swift 中絕大多數(shù)的情況下,推薦使用 String 類型

  • 使用 String 的原因
  • String 是一個結(jié)構(gòu)體,性能更高
    • String 目前具有了絕大多數(shù) NSString 的功能
    • String 支持直接遍歷
  • NSString 是一個 OC 對象,性能略差
  • Swift 提供了 StringNSString 之間的無縫轉(zhuǎn)換
  • 遍歷字符串
let str = "我要飛的更High"

for s in str {
    print(s)
}
  • 字符串拼接
let str1 = "zhangsan"
let str2 = "lisi"
let i = 10

print(str1 + str2) // "zhangsanlisi\n"
print("\(str1) \(str2) \(i)") // "zhangsan lisi 10\n"
  • 小結(jié)
    • 直接在 "" 中使用 \(變量名) 的方式可以快速拼接字符串
    • 小伙伴們再也不要考慮 stringWithFormat
  • 格式化字符串
for _ in 0...10 {
    let str = String(format: "zhangsan - %04d", arguments: [arc4random_uniform(100)])
    print(str) // (11 times) zhangsan - 0002
}
  • 小結(jié)
    • 在實際開發(fā)中,如果需要指定字符串格式,可以使用 String(format:...) 的方式
    • 注意:后面的參數(shù)需要放在一個數(shù)組中
  • String & Range 的結(jié)合

以下是超級費勁的代碼

let str: String = "beixinke"

var subStr = str.substringWithRange(Range<String.Index>(start: str.startIndex, end: str.endIndex))
print(subStr) // "beixinke\n"
  • 建議寫法
let str1: NSString = "beixinke" // "beixinke"
print(str1.substringWithRange(NSMakeRange(0, 3))) // "bei\n"
  • 字符串
    • OC的字符串是NSString, Swift的字符串String
    • OC的字符串是一個對象, Swift字符串是一個結(jié)構(gòu)體, 效率更高
    • OC中的字符串是一個\0結(jié)尾, Swift字符串不是以\0結(jié)尾
NSString *str = @"abc\0def";
NSLog("%@", str); // abc
  • Swift中的字符串支持遍歷
let str = "abc\0def" // "abc?def"
print(str) // "abc?def\n"

// 遍歷字符串
for c in str.characters
{
    print(c) // (7 times)
}

// 字符串拼接
var str2 = "gcy"
str2 += str
str2 // "gcyabc?def"

// 字符串格式化
// 可以使用\()在字符串中插入任何數(shù)據(jù)
let name = "gcy"
let age = 30
let res = "name = \(name), age = \(age)"
res // "name = gcy, age = 30"

// 2015-10-09 03:04
let str3 = String(format: "%d-%02d-%02d %02d:%02d", arguments: [2015, 10, 9, 3, 4]) // "2015-10-09 03:04"

// 截取字符串
// 提示: 在Swift開發(fā)中, 我們經(jīng)常需要將Swift的字符串轉(zhuǎn)換為OC的字符串來操作, 并且Swift自身也意識到了這一點, 所以在OC字符串和Swift的字符串之間轉(zhuǎn)換相當(dāng)簡單
let str4 = "beixinke"
//let str5: NSString = str4
//str5.substringToIndex(4)
//str5.substringWithRange(NSMakeRange(4, 2))

// as 就是把什么當(dāng)做什么
(str4 as NSString).substringWithRange(NSMakeRange(4, 2)) // "in"

  • 10.函數(shù)
  • 簡單演練
func sum(a: Int, b: Int) -> Int {
    return a + b
}
  • 小結(jié)
    • 函數(shù)定義格式:func 函數(shù)名(參數(shù): 參數(shù)類型...) -> 返回值 { // 代碼實現(xiàn) }
    • 如果沒有返回值, -> 返回值 可以省略
    • -> 是一個很有意思的符號
    • 默認(rèn)情況下,在調(diào)用函數(shù)時,第一個參數(shù)名是省略的
    • Void == ()
  • 參數(shù)名的特殊處理

  • 強制要求參數(shù)名

func sum1(x a: Int, y b: Int) -> Int {
    return a + b
}
  • 省略參數(shù)名
func sum2(a: Int, _ b: Int) -> Int {
    return a + b
}
// 1.沒有參數(shù)沒有返回值
func say() -> Void
{
    print("hi") // "hi\n"
}
say()
// 如果沒有返回值可以簡寫
func say1() -> ()
{
    print("hi") // "hi\n"
}
say1()

func say2()
{
    print("hi") // "hi\n"
}
say2()


// 2.有參數(shù)沒有返回值
// Swift2.0開始, 會自動將形參列表的第二個參數(shù)名稱作為標(biāo)簽
// Swift2.0之前是沒有這個特性的, 在Swift2.0之前如果需要顯示標(biāo)簽需要在形參名稱前面加上#
func sum(num1: Int, num2: Int)
{
    print(num1 + num2) // "30\n"
}
sum(10, num2: 20)


// 3.沒有參數(shù)有返回值
func getNumber() -> Int
{
    return 998
}
print(getNumber()) // "998\n"

// 4.有參數(shù)有返回值
func sum2(num1: Int, num2: Int) -> Int
{
    return num1 + num2
}
print(sum2(50, num2: 50)) // "100\n"


// 內(nèi)部和外部參數(shù)
/*
* 默認(rèn)情況下所有形參都是內(nèi)部參數(shù), 也就是說只能在函數(shù)內(nèi)部使用
* 從Swift2.0開始會自動將形參列表的第二個參數(shù)名稱作為標(biāo)簽, 也就是說從第二個參數(shù)開始, 參數(shù)的名稱既是內(nèi)部參數(shù)又是外部參數(shù)
* 如何指定外部參數(shù)?
*/
func sum3(num1: Int, y num2: Int)
{
    print("num1 = \(num1), num2 = \(num2)") // "num1 = 10, num2 = 20\n"
    print(num1 + num2) // "30\n"
}
//sum3(10, num2: 20)
sum3(10, y: 20)

// 默認(rèn)參數(shù)
// 如果指定了默認(rèn)值, 那么在調(diào)用方法的時候就可以不用傳遞數(shù)據(jù), 如果不傳遞數(shù)據(jù)系統(tǒng)就會使用默認(rèn)值, 如果傳遞了就會使用傳遞的值
// 在其它語言里面, 默認(rèn)值一般情況只能是最后一個參數(shù), 但是Swift可以寫在任何位置
func joinString(str1: String, str2: String = "在", str3: String) -> String
{
    return str1 + str2 + str3 // (2 times)
}
joinString("gcy", str2: "也在", str3: "bxk") // "gcy也在bxk"
joinString("wy", str3: "bxk") // "wy在bxk"


// 常量參數(shù)和變量參數(shù)以及inout參數(shù)
// 默認(rèn)情況下所有形參都是常量參數(shù), 不能在函數(shù)中修改形參的值
// 如果想在函數(shù)中修改形參的值, 那么必須把形參變?yōu)樽兞繀?shù)
// 和OC一樣, 在函數(shù)中修改形參的值不會影響到外面實參的值
// 如果想在函數(shù)中修改形參之后影響實參, 那么必須把形參變?yōu)閕nout參數(shù)

//func swap(a: Int, b: Int)
//{
//    let temp = a
//    a = b  // 不能修改常量參數(shù)
//    b = temp
//}

//func swap(var a: Int, var b: Int)
//{
//    print("a = \(a), b = \(b)")
//    let temp = a
//    a = b
//    b = temp
//    print("a = \(a), b = \(b)")
//}

func swap(inout a: Int, inout b: Int)
{
    print("a = \(a), b = \(b)") // "a = 10, b = 20\n"
    let temp = a // 10
    a = b // 20
    b = temp //10
    print("a = \(a), b = \(b)") // "a = 20, b = 10\n"
}

var x = 10
var y = 20
print("x = \(x), y = \(y)") // "x = 10, y = 20\n"
swap(&x, b: &y)
print("x = \(x), y = \(y)") // "x = 20, y = 10\n"

// 可變參數(shù)
// 只要參數(shù)是可變參數(shù), 就可以傳遞一個或多個值
// 在其它語言中一般情況下可變參數(shù)只能是最后一個形參, 而Swift中可以寫在任意位置, 但是為了提高代碼的閱讀性, 還是建議寫在最后
func sum4(nums: Int..., temp: Int) -> Int
{
    var sum = 0 // 0
    for i in nums
    {
        sum += i // (3 times)
    }
    return sum + temp // 16
}
sum4(1, 2, 3, temp: 10) // 16

// 函數(shù)嵌套
// 將一個函數(shù)寫到另外一個函數(shù)的函數(shù)體中, 外面稱之為函數(shù)嵌套
// 1.被嵌套的函數(shù)只能在父函數(shù)內(nèi)部訪問
// 2.被嵌套的函數(shù)可以訪問外部的變量
// 應(yīng)用場景: 兩個函數(shù)之間依賴較強, 或者一個函數(shù)就只給另外一個函數(shù)使用
//          例如: 對數(shù)組排序是一個函數(shù), 交換變量又是一個函數(shù), 他們就可以使用函數(shù)嵌套
let value = 55 // 55
func test()
{
    let number = 10 // 10
    func demo()
    {
        print("----\(number), \(value)") // "----10, 55\n"
    }
    demo()
}
test()

  • 11.構(gòu)造函數(shù)
    • Swift中要求在創(chuàng)建一個類時必須給這個類中所有的屬性進行初始化
    • 如果不能在創(chuàng)建對象時給這個類中所有的屬性進行初始化, 那么這些屬性必須是可選的
    • 如果已經(jīng)在構(gòu)造方法中對所有的屬性進行了初始化, 那么這些屬性就可以不是可選類型
    • 在給某一個類指定屬性的數(shù)據(jù)類型時, 如果該屬性是對象類型, 那么可以指定為可選類型
    • 如果該屬性不是對象類型而是基本數(shù)據(jù)類型, 那么建議直接賦值為0
      • 調(diào)用 super.init()的目的主要是為了給對象分配存儲空間
    • Swift中如果想在構(gòu)造方法中使用KVC轉(zhuǎn)換模型, 必須先調(diào)用 super.init()
class Person: NSObject {

    var name: String?
    // 如果屬性是基本數(shù)據(jù)類型, 并且是可選類型, 系統(tǒng)不會自動分配存儲空間
    var age: Int = 0

//    var name: String
//    var age: Int


    // Person()
    override init() {
        // 注意: 在構(gòu)造方法中必須先初始化本類再初始化父類
        name = "gcy"
        age = 24
        // 當(dāng)我們重寫一個類的構(gòu)造方法時, 系統(tǒng)內(nèi)部會悄悄的幫我們調(diào)用super.init()
        super.init()

    }


    // 自定義構(gòu)造方法
    init(name: String, age: Int)
    {
        self.name = name
        self.age = age
//        以下這一句代碼, 能不寫就不寫
//        super.init()
    }

    init(dict: [String: AnyObject])
    {
        // 注意:Swift中如果想在構(gòu)造方法中使用KVC轉(zhuǎn)換模型, 必須先調(diào)用 super.init()
        super.init()
        setValuesForKeysWithDictionary(dict)
    }

    // Swift中打印對象會調(diào)用下面這個屬性
    override var description: String {
//        return "name = \(name), age = \(age)"
        let property = ["name", "age"]
        let dict = dictionaryWithValuesForKeys(property)
        return "\(dict)"
    }
}
  • 注意: Swift開發(fā)中一般情況下不用導(dǎo)入頭文件, 因為只要所有的文件都在一個命名空間中那么就可以直接使用
  • 默認(rèn)情況下一個項目的命名空間就是項目名稱, 而在同一個項目下的所有文件都在同一個命名空間中
  • 如果自定義一個類, 并且沒有重寫構(gòu)造方法, 那么系統(tǒng)會提供默認(rèn)的構(gòu)造方法
  • 如果自定義一個類, 并且自定義了構(gòu)造方法, 那么系統(tǒng)不會提供默認(rèn)的構(gòu)造方法

  • 12.getter & setter
    • 自定義 Person 類
class Person: NSObject {

    var name: String?
    var age: Int?
}
  • getter & setter
var _name: String?

var name: String? {
    get {
        return _name
    }
    set {
        _name = newValue
    }
}
  • Swift 中以上形式的 getter & setter 很少用
  • didSet
  • 在 OC 中,我們通常希望在給某一個變量賦值之后,去做一些額外的操作
  • 最經(jīng)典的應(yīng)用就是在自定義 Cell 的時候,通過模型的設(shè)置方法完成 Cell 的填充
var length: Int? {
    didSet {
        timeStr = String(format: "%02d:%02d:%02d", arguments: [length! / 3600, (length! % 3600) / 60, length! % 60])
    }
}
var timeStr: String?
    var name: String?
        {
        // 在Swift開發(fā)中用以下兩個方法代替OC中的重寫setter方法
        willSet{
           print("賦值之前調(diào)用 \(newValue)")
        }
        didSet{
            print("賦值之后調(diào)用 \(oldValue)")
        }
    }
  • 計算型屬性
var title: String {
    get {
        return "Mr " + (name ?? "")
    }
}
  • 只實現(xiàn) getter 方法的屬性被稱為計算型屬性,等同于 OC 中的 ReadOnly 屬性
  • 計算型屬性本身不占用內(nèi)存空間
  • 不可以給計算型屬性設(shè)置數(shù)值
  • 計算型屬性可以使用以下代碼簡寫
var title: String {
    return "Mr " + (name ?? "")
}
  • 構(gòu)造函數(shù)
init(dict: [NSObject: AnyObject]) {
    name = dict["name"] as? String
    age = dict["age"] as? Int
}
  • 析構(gòu)函數(shù)
deinit {
    print("88")
}

  • 13.閉包
    • OC: block類似于匿名函數(shù), 用于封裝代碼塊, 在特定的時候執(zhí)行
    • 執(zhí)行一些耗時操作
    • 類型: 返回值類型(^block名稱)(形參列表)
           值:
            ^(形參列表){
                需要執(zhí)行的代碼
            }
  • Swift: 閉包是用于定義函數(shù)(Swift中函數(shù)就是閉包, 閉包就是一個特殊的函數(shù))
  • 執(zhí)行一些耗時操作
  • 類型: (形參列表)->返回值類型
    值:
    {
    (形參列表)->返回值類型
    in
    需要執(zhí)行的代碼
  • 閉包的幾種格式
    1. 完整寫法
    loadData ({ () -> () in
        print("更新UI")
    })
  • 2.如果閉包沒有形參, 那么in和in之前的代碼都可以省略
    loadData ({
        print("更新UI")
    })
  • 3.如果閉包是函數(shù)的最后一個參數(shù), 那么閉包可以寫在函數(shù)()的后面
    loadData (){
        print("更新UI")
    }
  • 4.如果函數(shù)只有一個閉包參數(shù), 那么函數(shù)的()可以省略
    loadData {
        print("更新UI")
    }
    func loadData(finished: ()->())
    {
        dispatch_async(dispatch_get_global_queue(0, 0)) { () -> Void in
            print(NSThread.currentThread())
            print("加載數(shù)據(jù)")

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                print(NSThread.currentThread())
                finished()
            })
        }
    }
  • 能用最簡單的就用最簡單的寫法

  • 閉包的參數(shù)和返回值

示例:
1.在控制器的View上添加一個UIScrollview, 然后在UIScrollview上添加15個按鈕, 讓按鈕平鋪
2.要求創(chuàng)建UIScrollview以及按鈕通過一個方法來創(chuàng)建
2.1并且按鈕的個數(shù)必須通過閉包來指定
2.2并且如何創(chuàng)建按鈕也必須通過閉包來指定(UIScrollview上面添加什么控件通過閉包傳遞)
        /*
        // 1.創(chuàng)建UIScrollview
        let sc = UIScrollView(frame: CGRect(x: 0, y: 200, width: UIScreen.mainScreen().bounds.width, height: 50))
        sc.backgroundColor = UIColor.redColor()

        // 2.通過循環(huán)創(chuàng)建15個按鈕
        let count = 15
        let width:CGFloat = 80
        let height = sc.bounds.height
        for i in 0..<count
        {
            let btn = UIButton()
            btn.setTitle("標(biāo)題\(i)", forState: UIControlState.Normal)
            btn.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
            btn.backgroundColor = UIColor.greenColor()
            // 3.將按鈕添加到UIScrollview上
            sc.addSubview(btn)
        }
        sc.contentSize = CGSize(width: CGFloat(count) *  width, height: height)

        // 4.將UIScrollview添加到控制器view上
        view.addSubview(sc)
        */

        let sc = createScrollview({ () -> Int in
            return 20
            }) { (index) -> UIView in
//                let btn = UIButton()
//                btn.setTitle("標(biāo)題\(index)", forState: UIControlState.Normal)
//                btn.backgroundColor = UIColor.greenColor()

                let label = UILabel()
                label.text = "標(biāo)題\(index)!!!"
                label.backgroundColor = (index % 2 == 0) ? UIColor.greenColor() : UIColor.purpleColor()
                return label
        }
        view.addSubview(sc)
    }

    // 技巧: 在編寫閉包代碼時, 不管三七二十一先寫上 ()->(), 然后再修改
    func createScrollview(getNumber: ()->Int, createView: (index: Int)->UIView) -> UIScrollView
    {
        // 1.創(chuàng)建UIScrollview
        let sc = UIScrollView(frame: CGRect(x: 0, y: 200, width: UIScreen.mainScreen().bounds.width, height: 50))
        sc.backgroundColor = UIColor.redColor()

        // 2.通過循環(huán)創(chuàng)建15個按鈕
        let count = getNumber()
        let width:CGFloat = 80
        let height = sc.bounds.height
        for i in 0..<count
        {
            /*
            let btn = UIButton()
            btn.setTitle("標(biāo)題\(i)", forState: UIControlState.Normal)
            btn.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)
            btn.backgroundColor = UIColor.greenColor()
            */
            let subView = createView(index: i)
            subView.frame = CGRect(x: CGFloat(i) * width, y: 0, width: width, height: height)

            // 3.將按鈕添加到UIScrollview上
            sc.addSubview(subView)
        }
        sc.contentSize = CGSize(width: CGFloat(count) *  width, height: height)

       return sc
    }

}
  • 閉包的循環(huán)引用
    // 注意: 在設(shè)置閉包屬性是可選類型時一定更要用一個()括住閉包的所有的類型, 否則只是指定了閉包的返回值是可選的
    // 錯誤寫法: var callback: ()->()?
    var callback: (()->())?

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {

        // OC中如何解決:  __weak typeof(self) weakSelf = self;
        // Swift中如何解決: weak var weakSelf = self
        // 對應(yīng)關(guān)系:  __weak == weak   __unsafe_unretained == unowned

//        weak var weakSelf = self
        loadData { [unowned self] () -> () in
            print("被回調(diào)了")

            // 在Swift開發(fā)中, 能不寫self就不寫slef
            // 一般情況下只有需要區(qū)分參數(shù), 或者在閉包中使用
//            self.view.backgroundColor = UIColor.greenColor()

//            weakSelf!.view.backgroundColor = UIColor.greenColor()

            self.view.backgroundColor = UIColor.greenColor()
        }
    }

    func loadData(finished: ()->())
    {
        callback = finished
        // 1.加載數(shù)據(jù)
        print("加載數(shù)據(jù)")

        // 2.執(zhí)行回調(diào)
        finished()
    }

    // deinit 相當(dāng)于OC中的dealloc方法
    // 只要一個對象釋放就會調(diào)用deinit方法
    deinit
    {
        print("88")
    }
}

  • 14.懶加載
  • 只有外界訪問到listData的時候才會去執(zhí)行閉包, 然后將閉包的返回值賦值給listData
  • 注意: 一定要記住閉包后面需要寫上(), 代表執(zhí)行閉包
lazy var listData: [String]? = {
        ()->[String]
        in
        print("---")
        return ["gcy", "cyh", "wy", "lsl"]
    }()

    // 開發(fā)中這樣寫
    lazy var listData2: [String]? = {
        print("---")
        return ["gcy", "cyh", "wy", "lsl"]
        }()

    lazy var listData3: [String]? = self.test()
    func test() -> [String]
    {
        print("+++")
        return ["gcy", "cyh", "wy", "lsl"]
    }

    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
        print(listData3)
        print(listData3)
        print(listData3)
        print(listData3)
    }

  • 15.單例模式
  • OC中
+ (instancetype)shareNetworkTools
{
    static NetworkTools *_instance;
    // onceToken默認(rèn)等于0, 只要執(zhí)行一次之后就不等于0了, 原理是通過判斷onceToken是否等于0決定是否需要執(zhí)行block
    static dispatch_once_t onceToken;
    NSLog(@"%ld", onceToken);
    dispatch_once(&onceToken, ^{
        _instance = [[NetworkTools alloc] init];
    });
    return _instance;
}
  • 如果在Swift中編寫單例, 推薦使用如下寫法
  • 而且蘋果有統(tǒng)一的命名規(guī)范,但凡是單例統(tǒng)一是用shareInstance
    /*
    static var onceToken: dispatch_once_t = 0;
    static var _instance: NetworkTools?

    class func shareNetworkTools() -> NetworkTools {
        print(onceToken)
        dispatch_once(&NetworkTools.onceToken, {
            _instance = NetworkTools()
        })
        return _instance!
    }
    */

    /*
    static let _instance: NetworkTools =  NetworkTools()
    class func shareNetworkTools() -> NetworkTools {
        return _instance
    }
    override init() {
        print("++++++")
    }
    */
static let shareInstance: NetworkTools =  NetworkTools()

  • 16.UITableView基本使用
// 1.在Swift中遵守協(xié)議直接利用逗號隔開
class ViewController: UIViewController {

    override func loadView() {
        let tableView = UITableView()
        tableView.dataSource = self
        tableView.delegate = self
        view = tableView
    }

    // MARK: - 懶加載
    lazy var  listData: [String]? = {
       return ["gcy", "cyh", "wy", "sz", "lsl", "fbk"]
    }()
}

// extension 相當(dāng)于OC的 Category
extension ViewController: UITableViewDataSource, UITableViewDelegate
{

    // MARK: - UITableViewDataSource
    func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }
    func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // TODO: 有問題, 開發(fā)中不應(yīng)該這樣寫
        return (listData?.count)!
    }
    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCellWithIdentifier("cell")
        if cell == nil
        {
            cell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: "cell")
        }

        cell?.textLabel?.text = listData![indexPath.row]

        return cell!

    }
    // MARK: - UITableViewDelegate
    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        print(listData![indexPath.row])
    }
}

17.變量類型推導(dǎo)

  • 在 swift 開發(fā)中,對象的類型是自動推導(dǎo)
  • 對象的準(zhǔn)確類型由創(chuàng)建對象時的代碼決定
  • 如果定義變量時,右側(cè)代碼具有歧義,可以在左側(cè)以 :類型 指定變量的類型,例如:
// 個人推薦
let i: CGFloat = 10
  • 也可以寫成
var j = 10 as? CGFloat
  • 如果某些方法返回的數(shù)據(jù)類型是 AnyObject/AnyClass,則需要在右側(cè)使用 as 類型 表明類型,并且根據(jù)返回值是否是可選項,添加 ! 或者 ?,例如:
let ns = NSBundle.mainBundle().infoDictionary!["CFBundleExecutable"] as! String
  • 如果某些方法返回類型是 AnyObject/AnyClass,但是對象類型是動態(tài)生成的,也就是說,編碼時同樣無法確定改對象的準(zhǔn)確類型,可以在左側(cè)使用 : AnyObject 或者 : AnyClass 告訴編譯器暫不處理,例如:
let cls: AnyClass = NSClassFromString(ns + "." + vcName)!

提示:as?as! 是剛接觸 swift 最令人煩惱的語法之一,蘋果也在這個語法規(guī)則上多次做過調(diào)整,在學(xué)習(xí)時建議:

  • 多用 option + click 查看對象信息
  • 借助 Xcode 智能提示修改

  • 18.guard--守護者--是swift2.0推出的。這樣就不會有嵌套中還有嵌套,避免了強制解包和循環(huán)嵌套
  • 在Swift中, 如果想通過字符串創(chuàng)建一個類, 那么必須加上命名空間
  • 動態(tài)獲取的命名空間是不包含.的, 所以需要我們自己手動拼接
  • 將AnyClass類型轉(zhuǎn)換為UIViewController類型
        /*
        蘋果也意識到了, Swift會不知不覺的形成多層嵌套, 然代碼變得非常丑陋
        所以Swift2.0的時候?qū)iT推出了一個條件語句(guard)來解決這個問題
        格式:
        guard 條件表達(dá)式 else {
            需要執(zhí)行的語句
            return
        }
        特點: 只要條件為假才會執(zhí)行else中的代碼
        作用: 用于過濾數(shù)據(jù)
        對比if else 這哥們只有else{}沒有if{}
        */



19.try catch

  • 在OC中處理異常是通過傳入一個NSError的指針來保存錯誤
  • Swfit中提供了專門處理異常機制 throws -> AnyObject
  • Swift中提供 try catch, 將有可能發(fā)生錯誤的代碼放到do中, 如果真的發(fā)生了異常就會執(zhí)行catch
    • try作用: 如果拋出(throws)異常, 那么就會執(zhí)行catch
    • try!作用: 告訴一定一定沒有錯誤, 不需要處理, 但是如果使用try!發(fā)生了錯誤, 那么程序就會崩潰, 開發(fā)中不推薦使用
    • try?作用: 告訴系統(tǒng)可能有錯也可能沒有錯, 如果發(fā)生錯誤會返回一個nil, 如果沒有發(fā)生錯誤, 會將數(shù)據(jù)包裝成可選類型
  • 在開發(fā)中如果說你拋了一個異常之后,你不想進行任何處理,就可以用try?這樣的話try?返回一個nil,程序也不會崩潰。對你就無關(guān)痛癢了。
  • 但是你如果用try!拋異常就會崩潰;
  • 但是如果你有try就一定要do...catch否則就會報錯

throw catchXcode 7.0 對錯誤處理的一個非常大的變化

  • 范例代碼
// 2. 反序列化
// 1.獲取json文件路徑
        let jsonPath = NSBundle.mainBundle().pathForResource("MainVCSettings.json", ofType: nil)
        // 2.加載json數(shù)據(jù)
        let jsonData = NSData(contentsOfFile: jsonPath!)
        // 3.序列化json
        do{
             // throw是Xcode7最明顯的一個變化, Xcode7之前都是通過傳入error指針捕獲異常, Xocode7開始通過try/catch捕獲異常
            let dictArray = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers)

            // 遍歷字典時候需要明確指明數(shù)組中的數(shù)據(jù)類型
            for dict in dictArray  as! [[String:String]]
            {
                 // 由于addChildVC方法參數(shù)不能為nil, 但是字典中取出來的值可能是nil, 所以需要加上!
                addChildViewController(dict["vcName"]!, title: dict["title"]!, imageName: dict["imageName"]!)
            }
        }catch{
            print(error)
            addChildViewController("HomeTableViewController", title: "首頁", imageName: "tabbar_home")
            addChildViewController("MessageTableViewController", title: "消息", imageName: "tabbar_message_center")
            addChildViewController("DiscoverTableViewController", title: "發(fā)現(xiàn)", imageName: "tabbar_discover")
            addChildViewController("ProfileTableViewController", title: "我", imageName: "tabbar_profile")
        }
  • 如果能確保代碼執(zhí)行正確,可以強行 try!
let array = try! NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers)

不過需要注意的是,一旦解析錯誤,程序會直接崩潰!



20.private

  • 在swift中,里面的東西都是能夠全局訪問的,如果你只想只在本文件訪問的話,就加上一個private
    • 如果在方法前面加上private, 代表這個方法只能在當(dāng)前文件中訪問
    • 如果在屬性前面加上private, 代表這個屬性只能在當(dāng)前文件中訪問
    • 如果在類前面加上private, 代表這個類只能在當(dāng)前文件中訪問
  • private也有利于程序員之間的溝通,一看到就知道是和本文件有關(guān),不提供外界使用,點擊事件加上@objc就可以知道是關(guān)于點擊事件
  • 提高閱讀性,記得用// MARK: - ?內(nèi)容


21.便利構(gòu)造器

  • 在Swift開發(fā)中, 如果想快速創(chuàng)建一個對象, 那么可以提供一個便利構(gòu)造器(便利構(gòu)造方法--用于快速創(chuàng)建對象)
  • 只要在普通構(gòu)造方法前面加上一個convenience, 那么這個構(gòu)造方法就是一個便利構(gòu)造方法
  • 注意: 如果定義一個便利構(gòu)造器, 那么必須在便利構(gòu)造器中調(diào)用指定構(gòu)造器(沒有加convenience單詞的構(gòu)造方法)
    • 遍歷構(gòu)造方法的參數(shù)不能指定默認(rèn)參數(shù)
import UIKit

extension UIButton
{
    class func create(imageName: String, backImageName: String) -> UIButton
    {
        let btn = UIButton()
        // 1.設(shè)置背景圖片
        btn.setBackgroundImage(UIImage(named: imageName), forState: UIControlState.Normal)
        btn.setBackgroundImage(UIImage(named: imageName + "highlighted"), forState: UIControlState.Highlighted)

        // 2.設(shè)置普通圖片
        btn.setImage(UIImage(named:backImageName), forState: UIControlState.Normal)
        btn.setImage(UIImage(named: backImageName + "highlighted"), forState: UIControlState.Highlighted)

        btn.sizeToFit()

        return btn
    }
    // 雖然以上方法可以快速創(chuàng)建一個UIButton對象, 但是Swift風(fēng)格不是這樣寫的
    // 在Swift開發(fā)中, 如果想快速創(chuàng)建一個對象, 那么可以提供一個便利構(gòu)造器(便利構(gòu)造方法--用于快速創(chuàng)建對象)
    // 只要在普通構(gòu)造方法前面加上一個convenience, 那么這個構(gòu)造方法就是一個便利構(gòu)造方法
    // 注意: 如果定義一個便利構(gòu)造器, 那么必須在便利構(gòu)造器中調(diào)用指定構(gòu)造器(沒有加convenience單詞的構(gòu)造方法)

    /*
    定義便利構(gòu)造器步驟:
    1.編寫一個構(gòu)造方法
    2.在構(gòu)造方法前面加上 convenience
    3.在構(gòu)造方法中調(diào)用當(dāng)前類的其他"非便利構(gòu)造器"初始化對象
    */
    convenience init(imageName: String, backImageName: String)
    {
        self.init()

        // 1.設(shè)置背景圖片
        setBackgroundImage(UIImage(named: imageName), forState: UIControlState.Normal)
        setBackgroundImage(UIImage(named: imageName + "highlighted"), forState: UIControlState.Highlighted)

        // 2.設(shè)置普通圖片
        setImage(UIImage(named:backImageName), forState: UIControlState.Normal)
        setImage(UIImage(named: backImageName + "highlighted"), forState: UIControlState.Highlighted)

        sizeToFit()
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,263評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,946評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,708評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,186評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,409評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,774評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,976評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,641評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,872評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,650評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,958評論 2 373

推薦閱讀更多精彩內(nèi)容