前言
已經很久沒有在簡書上更新了, 最近一直在忙于開發業務, 實在沒有太多時間來沉淀, 再機上比較懶, 所以就一直沒有更新了. 好不容易看了一些和繪圖性能相關的東西, 但是因為有的大牛已經講的比較清楚了, 所以也不多贅述什么了, 有興趣的可以去看YYKit作者寫的iOS 保持界面流暢的技巧, 任何關注繪圖性能的同學都應該仔細讀讀這一篇博客
原因
Swift目前已經到了2.1版, 總算是相對穩定了, 之前有關注, 但是并不打算快速切入, 畢竟只是初版, 之后改動的可能性也是很大的, 加之那個時候切入, 其他的小伙伴也不一定愿意接受, 到時候只能自己維護自己的代碼, 還要去改別人的代碼, 要切換思維, 還是很浪費時間且沒有效率的事情.
稍微談一下我被Swift吸引的地方吧, 一個是optional value, 一個是面向協議編程, 還有就是extension
我目前也在學習中, 資料是蘋果自己出的資料包括iBooks里面的和WWDC的視頻, 我也會跟著資料一篇篇講下去, 講一些我覺得比較關鍵的點或者是需要注意的地方. 到時候會持續更新, 歡迎大家一起探討, 有誤之處還請大家指正.
基本變化
- 語法風格完全脫離了ObjC, 與Java類似了
- 每一條語句不需要;結尾了, 但是結尾也不會報錯, 大多數情況下;都沒有什么用了, 還有就是對空格要求嚴格一些了, 有些地方必須要空格,不然會報錯的
- 沒有宏定義了
- 條件判斷不需要括號包圍了
- 增加了大量的關鍵字, 不用也可以, 但是用了會使得代碼很簡潔易懂
- 去掉了block, 引入了closure(閉包), 其實差不多的作用, 就是寫法不同
- 沒有了id類型, 換成了AnyObject
- switch的匹配更加靈活強大, 而不僅限于ObjC里面的整數, 而且對每個case都是自動添加break
...
還是不一一列舉了, 畢竟是一門全新的語言, 一直舉下去也沒什么意義, 還是直接切入正題吧. PS: 大家多用playground來測試代碼吧 還是很方便的, 就是代碼多了會慢一點
基礎篇(The Basics)
- Swift中用var來聲明變量, let來聲明常量. 導致了Swift里面只有Array類型, 沒有MutableArray類型(其它的集合類型也是一樣), 因為var則代表可變, let則代表不可變. 例如:
var varArray: Array = [AnyObject]() // 初始化一個空數組, 可以看到, AnyObject就代表著id
varArray.append(1) // 插入一個整數, 注意, 這里不需要@1, 在Swift Int也是一個對象(不是int)
varArray.append("2") // 字符串也不需要@了
let constArray: Array = [1,2,3] // 不可變數組
constArray.append(3) // error: 不可以向不可變的數組插入元素
類型推導: 聲明變量如果賦了初值, 那么就可以省略掉后面的類型, 例如:
var number = 1 // 編譯器通過 = 1來推導出number類型為Int變量名支持Unicode編碼字符, 這個我覺得沒什么用, 應該沒有人會真的用吧?
打印函數: print, 與C++類似, 支持重名函數, 所以print有多種用法, 但是都比較容易懂, playground實驗一下就好, 個人感覺還是很方便的, 例如:
let name = "Ryan"
print("My name is \(name)") // 直接用\(variable)的方式直接代入變量
之前說了分號(;)很少用了, 代表還是有用的地方的, 比如你要在一行里面執行多條語句,就用分號(;)分割
Bool值由YES,NO改為了更加常見的true和false, 同時整數0與非0不能再代表false和true了, 因為Int沒有實現BooleanType協議, 這是蘋果故意的, 因為你自己extension Int: BooleanType的話, 編譯器會明確告訴你, 不允許這么干, 應該是蘋果想開發者更顯式的寫明條件, 避免出現意外的錯誤
元組(Tuples)
元組是一個很棒的東西, 以前在寫C語言的時候, 因為返回值只能返回一個東西, 所以還要特意傳入一個變量的地址來寫入額外的信息, 或者返回一個結構體, OC里面也差不多是這樣的, Swift引入了元組就更加強大了, 可以返回多個值, 用()包起來就可以了, 我估計其實是編譯器幫我們實現了一個結構體, 例子:
let http404Error = (404, "Not Found") // 默認用http404Error.0/.1來訪問404和"Not Found", 如果要指定, 則let http404Error = (code:404, reason:"Not Found"), 當然.0和.1還是可用的.
// 通過數據的訪問形式, 我們的確是可以猜測其實就是編譯器自己實現了一個結構體
Tip:元組在用法可不止這些, 還可以寫出最簡單的交換2個變量的值的代碼. 以前我們都是, t = a, a = b, b = t 這種類型的寫法, 整型還有更簡單的寫法, 但是用元素就是一行代碼:
(a,b) = (b,a)
- Optionals: (我還是保持原文吧, 翻譯為可選類型總是感覺很奇怪).
這個東西其實和ObjC新引入nullable差不多, 就是告訴開發者這個東西可能是為nil, 你要好好判斷一下, 如果不判斷就用, 首先會有編譯報錯, 告訴你要用感嘆號(!)來獲得這個值(數據叫做Unwrapping), 然后你解決了這個問題, 但是它其實可能是為空的, 到時候就會導致runtime error, 直接給掛了. 所以, 蘋果說Swift的安全, 這是其一, 例子:
var serverResponseCode: Int?
serverResponseCode = 1
//var code: Int = serverResponseCode // error: 要用!來取值
if convertedNumber != nil { // 先判斷, 后使用
print("convertedNumber has an integer value of \(convertedNumber!).")
}
至于optional binding, 其實就是賦值一次, 省略了感嘆號(!)但是加了一個if let(if let得到的是常量, 所以也會有if var的), 如: // 1.30更新, 增加if var
var possibleNumber = "a12"
if let actualNumber = Int(possibleNumber) {
print("\'\(possibleNumber)\' has an integer value of \(actualNumber)")
} else {
print("\'\(possibleNumber)\' could not be converted to an integer")
}
正如官方而言, Optional value是一個黑盒子, 在使用之前不之前里面是有東西還是空的, 這也就是是為什么你要用!來取值, 不然你取的就是這個盒子.
// 1.25日添加:
Optional還有一種加感嘆號(!)的用法, 這種用法讓你直接回到了ObjC的寫法上了, 不需要額外去拆包, 但是很可惜, Swift對nil發送消息是會crash的, 所以要謹慎, 畢竟這種寫法是不安全的. 例如:
var aStr: String!
//aStr.characters.count //runtime error
aStr = "123"
aStr.characters.count // print 3
- 錯誤處理:
錯誤處理是一大塊內容, 這里先點一下, 按照Swift的設計, 拋出異常在Swift里面應該會用的比ObjC更多, 一個函數通過throws來拋出異常, 調用函數的地方用do, try, catch來捕獲, 如:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch Error.OutOfCleanDishes {
washDishes()
} catch Error.MissingIngredients(let ingredients) {
buyGroceries(ingredients)
}
至于為什么要加個do, 而不是Java里面的直接try+catch, 我覺得應該是異常處理其實是比較影響性能的, 所以ObjC是不推薦用異常來處理錯誤的, 因為能少try的語句盡量少try, 所以上面的例子中, 實際上只對makeASandwich()進行了try, 而eatASandwich()則沒有, 這樣可以讓盡量少的代碼在try里面, 提高性能. 哈, 個人猜測...
- 斷言:
沒什么特別的, 和之前的差不多, 例如:
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
值得關注的是, 到底什么時候該用斷言, 什么時候不該用? 蘋果的說法是:
a.下標越界的時候用
b. 如果傳入了一個無效的參數, 不滿足函數的需求
c. 傳入了nil, 但是函數本身需要一個非nil的參數
assertion可以在開發階段就把問題通過crash的方式暴露出來, 而不是出現奇奇怪怪的結果, 然后一步步斷點去查. 當然, 記得在Xcode中設置, release打包中去掉斷言crash的選項...
這一部分值得說道的差不多就這么多了, 具體可以參考蘋果的文檔
里面對數值類型做了很多有意思的介紹, 比如老外喜歡千分位, 1000000要寫成1,000,000, 在代碼里面1000000不能一眼就看出來是多少, 所以有這樣的寫法:
var oneMillion = 1_000_000, 估計是編譯器看到數值類型有_就直接刪掉了.
還有很多有意思的tip, 但是用的地方可能不多就不多說了, 大家自己去探索吧.
基本運算符(Basic Operators)
其實這一章更加簡單, 基本上沒有差別, 只是Swift和C++一樣, 也有也運算符重載, 可以豐富很多寫法.
這里只記錄一些區別的地方:
- 賦值語句不再有返回值, 所以以前在ObjC里面寫的
if (self = [super init])
{
// ...
}
在Swift里面還這么玩就報錯了, 其實這是對原本要寫==寫成=的一種保護吧
- 三目運算符:
三目運算符不知道各位用的多不多, 我個人用的比較多, 比如我的block執行宏就是
#define RUN_BLOCK_IF_NONNIL(block,...) !(block)?:(block)(__VA_ARGS__);
這里對block進行為空判斷, 為空則返回自身, 也就是nil, 否則傳入參數執行之.
但是對于第一個參數返回自身省略的寫法, Swift是這樣的:
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
用??替換掉了?:
但是, 普通的用法, 也就是:前后都寫的, 還是一樣的
- 求余數(%):
在C和ObjC里面, %都只能對整數使用, 但是Swift進行了拓展, 可以對浮點數使用了:
8 % 2.5 // 結果為 0.5
- 范圍操作符:
也就是表示范圍的, 有兩種寫法: 1...3 代表1, 2, 3, 如果不想包含后面的數字, 就要寫成1..<3. (話說之前的版本是用..來代表..<的, 在新版進行了修改)
除此之外, Swift專門有個Range類型來表示之:
var range: Range = 1...3 // 會被編譯器描述成1..<4
其它的操作符基本上的一直的, 想要查看細節可以看[蘋果文檔](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/BasicOperators.html#//apple_ref/doc/uid/TP40014097-CH6-ID60)