2014年6月2號(hào)烫罩,蘋(píng)果發(fā)布了一個(gè)新的面向?qū)ο蟮恼Z(yǔ)言:Swift赏迟,做為Objective-C的替代者洪己。作為一門(mén)新的語(yǔ)言妥凳,Swift在簡(jiǎn)單易用上面獲得了大量的好評(píng),從而它的上升速度是非炒鸩叮快的逝钥。
從圖中可以看到,Swift的排名已經(jīng)超越了Objective-C噪珊。雖然在中國(guó)可能還大部分在使用Objective-C開(kāi)發(fā)晌缘,但是逐漸轉(zhuǎn)換為Swift是一個(gè)不可逆的趨勢(shì)。
接下去我們將從以下10個(gè)方面展示Swift和Objective-C的不同痢站。
- 可選(Optionals)
- 控制流
- 類(lèi)型推斷
- 元組
- 字符串操作
- Guard&Defer
- 函數(shù)式編程
- 枚舉
- 函數(shù)
- Do關(guān)鍵字
可選
可選的概念在C或者Objective-C中是不存在的磷箕。它意味著這個(gè)返回值可能有或可能為nil。我們知道阵难,在Objective-C中岳枷,一個(gè)方法可能返回一個(gè)對(duì)象或可能返回nil。但是對(duì)于基本類(lèi)型int呜叫、float等空繁,則是沒(méi)有可選的返回的。但是對(duì)于Swift而言朱庆,則是
let a = "48"
let b = Int(a)
print(b!)
//output
Optional(48)
Int函數(shù)這邊返回一個(gè)可選類(lèi)型盛泡,里面包含一個(gè)48的值。但是如果原先的字符串不是數(shù)字呢娱颊?
let aa = "error"
let bb = Int(aa)
print(bb)
//output
nil
從這邊我們可以看到傲诵,它返回了一個(gè)nil。因?yàn)镮nt函數(shù)無(wú)法將非數(shù)字的字符串轉(zhuǎn)換為Int箱硕。
我們知道對(duì)于Objective-C拴竹,如果你對(duì)nil發(fā)送消息,那將什么都不會(huì)發(fā)生剧罩。但是對(duì)于Swift栓拜,編譯器則會(huì)直接報(bào)錯(cuò)。
var x = Int("188")
print(x+1)
//output
error
如果要使用的話(huà),就必須強(qiáng)制解包幕与,可以用以下兩種方式:
var x = Int("188")
print(x!+1) //1.強(qiáng)制解包
if var y = x { //2.optional綁定
y += 811
print(y)
}
控制流
對(duì)于C語(yǔ)言或者Objective-C挑势,你可能對(duì)({})非常熟悉。if語(yǔ)句或者for語(yǔ)句都會(huì)用到纽门⊙Τ埽或者可以簡(jiǎn)寫(xiě)去掉({})营罢。但是對(duì)于Swift赏陵,你必須使用{},但是()可以去掉饲漾。
let xx = 4
if xx < 5 {
print(xx)
}
類(lèi)型推斷
Swift引入了類(lèi)型安全機(jī)制蝙搔。一旦一個(gè)變量被申明為一個(gè)類(lèi)型,那么就不能再改變了考传。同時(shí)編譯器能夠根據(jù)賦的值推斷出相應(yīng)的類(lèi)型吃型。
var str = "Some string"
// OR
var str2:String
str2 = "Other string"
而對(duì)于Objective-C,你必須顯式的申明一個(gè)變量:
NSString str = @"There is no type inference in Objective-C :("
元組
Swift支持元組類(lèi)型僚楞,它存儲(chǔ)一組值勤晚。跟數(shù)組不同,元組中的類(lèi)型不必相同的泉褐。比如:
var t:(String, Int) = ("John", 33)
print(t.0, t.1)
var j:(name:String, Int) = ("Morgan", 52)
print(j.name, j.1)
元組使用最多的是在函數(shù)的返回中:
var arr = [23, 5, 7, 33, 9]
func findPosition(el:Int, arr:[Int]) -> (found:Bool, position:Int)? {
if arr.isEmpty {
return nil
}
for (i, value) in arr.enumerated() {
if value == el {
return (true, i)
}
}
return (false, -1)
}
if let (isFound, elPosition) = findPosition(el: 5, arr: arr) {
print(isFound, elPosition)
// true 1
}
在Objective-C中赐写,可以用BLOCK來(lái)實(shí)現(xiàn)相似的效果,但是跟元組相比膜赃,顯然麻煩多了挺邀。
字符串操作
Swift在字符串操作上面相比Objective-C有巨大的提高。你不必為可變和非可變字符串困擾跳座,對(duì)于不可變的端铛,就使用let,對(duì)于可變的是疲眷,就使用var.
在Swift中禾蚕,字符串聚合是非常方便的:
// Swift:
var str = "My string"
str += " and another string”
而在Objective-C中,則是非常麻煩的狂丝。
// Obj-C:
NSString *myString = @"My string";
myString = [NSString stringWithFormat:@"%@ and another string", myString];
同時(shí)在Objective-C你需要使用占位符來(lái)表示不同類(lèi)型的數(shù)據(jù)换淆。但是在swift則完全不需要,直接用()包含就行美侦。
var str = "String: \(myString) | Signed 32-bit integer: \(myInt) | 64-bit floating-point number: \(myFloat)"
Guard&Defer
在Objective-C中产舞,當(dāng)你邏輯復(fù)雜,需要層層判斷時(shí)菠剩,往往會(huì)出現(xiàn)以下代碼:
enum TriangleAreaCalcError: Error {
case AngleNotSpecified
case InvalidAngle
case SideANotSpecified
case SideBNotSpecified
}
func calcTriangleArea(a: Double? , b : Double? , alpha : Double? ) throws -> Double {
if let a = a {
if let b = b {
if let alpha = alpha {
if alpha < 180 && alpha >= 0 {
if alpha == 180 {
return 0
}
return 0.5 * a * b * sin(alpha * Double.pi / 180.0)
} else {
throw TriangleAreaCalcError.InvalidAngle
}
} else {
throw TriangleAreaCalcError.AngleNotSpecified
}
} else {
throw TriangleAreaCalcError.SideBNotSpecified
}
} else {
throw TriangleAreaCalcError.SideANotSpecified
}
}
這看上去就像一個(gè)金字塔冕碟,可讀性非常差。而在Swift中啦桌,你可以使用guard關(guān)鍵字。它表示如果條件不滿(mǎn)足哈蝇,則進(jìn)入邏輯。
func calcTriangleArea(a: Double? , b : Double? , alpha : Double? ) throws -> Double {
guard
let a = a
else {
throw TriangleAreaCalcError.SideANotSpecified
}
guard
let b = b
else {
throw TriangleAreaCalcError.SideBNotSpecified
}
guard
let alpha = alpha
else {
throw TriangleAreaCalcError.AngleNotSpecified
}
if alpha == 180 {
return Double(0)
}
guard alpha < 180 && alpha >= 0
else {
throw TriangleAreaCalcError.InvalidAngle
}
return 0.5 * a * b * sin(alpha * Double.pi / 180.0)
}
Swift同時(shí)提供了defer關(guān)鍵字攘已,用于在退出當(dāng)前范圍之前執(zhí)行的操作邏輯炮赦。
func someImageFunc() -> UIImage? {
let dataSize: Int = 64
let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: dataSize)
// ...
guard error1
else {
destData.dealloc(dataSize) // #1
return nil
}
guard error2
else {
destData.dealloc(dataSize) // #2
return nil
}
guard error3
else {
destData.dealloc(dataSize) // #3
return nil
}
destData.dealloc(dataSize) // #4
// ...
}
從中我們可以看到,執(zhí)行了4次dealloc函數(shù)來(lái)保證在退出函數(shù)之前指針被釋放样勃。但是有了defer之后吠勘,我們只要寫(xiě)一次就可以了
func someImageFunc() -> UIImage? {
let dataSize: Int = 64
let destData = UnsafeMutablePointer<UInt8>.allocate(capacity: dataSize)
// ...
defer {
destData.dealloc(dataSize)
}
guard error
else {
return nil
}
guard error2
else {
return nil
}
guard error3
else {
return nil
}
// ...
}
函數(shù)式編程
Swift引入了大量函數(shù)式編程特征,比如map和filter峡眶,它可以在任何實(shí)現(xiàn)了CollectionType協(xié)議的集合上使用剧防。
let a = [4, 8, 16]
print(a.map{$0 / 2})
// [2, 4, 8]
let b:[(name:String, area:String)] = [("John", "iOS"), ("Sam", "Android"), ("Paul", "Web")]
let c = b.map({"Developer \($0.name) (\($0.area))"})
// ["Developer John (iOS)", "Developer Sam (Android)", "Developer Paul (Web)”]
let d = [23, 5, 7, 12, 10]
let e = d.filter{$0 > 10}
print(e) // [23, 12]
let sum = (20...30)
.filter { $0 % 2 != 0 }
.map { $0 * 2 }
.reduce(0) { $0 + $1 }
print(sum) // 250
而Objective-C原生是不支持這些函數(shù)式編程特征的,除非使用第三方庫(kù)辫樱。
枚舉
在Swift中峭拘,枚舉是非常強(qiáng)大的。它可以包含方法狮暑,可以傳參等鸡挠。以下列舉了一些用法:
enum Location {
case Address(city: String, street: String)
case Coordinates(lat: Float, lon: Float)
func printOut() {
switch self {
case let.Address(city, street):
print("Address: " + street + ", " + city)
case let.Coordinates(lat, lon):
print("Coordiantes: (\(lat), \(lon))")
}
}
}
let loc1 = Location.Address(city: "Boston", street: "33 Court St")
let loc2 = Location.Coordinates(lat: 42.3586, lon: -71.0590)
loc1.printOut() // Address: 33 Court St, Boston
loc2.printOut() // Coordiantes: (42.3586, -71.059)
枚舉同時(shí)可以遞歸,通過(guò)indirect關(guān)鍵字來(lái)實(shí)現(xiàn)
enum List {
case Empty
indirect
case Cell(value: Int, next: List)
}
let list0 = List.Cell(value: 1, next: List.Empty)
let list1 = List.Cell(value: 4, next: list0)
let list2 = List.Cell(value: 2, next: list1)
let list3 = List.Cell(value: 6, next: list2)
let headL = List.Cell(value: 3, next: list3)
func evaluateList(list: List) - > Int {
switch list {
case let.Cell(value, next):
return value + evaluateList(next)
case .Empty:
return 0
}
}
print(evaluateList(headL)) // 16
函數(shù)
Swift的函數(shù)語(yǔ)法是非常隨意的搬男,既可以像C語(yǔ)言風(fēng)格的拣展,也可以像Objective-C語(yǔ)言風(fēng)格的。在Swift中止后,每個(gè)函數(shù)都有一個(gè)類(lèi)型瞎惫,它由函數(shù)的參數(shù)和返回值組成。這表示你能夠指定函數(shù)的變量或者把函數(shù)作為參數(shù)傳給另一個(gè)函數(shù)译株。
func stringCharactersCount(s: String) -> Int {
return s.characters.count
}
func stringToInt(s: String) -> Int {
if let x = Int(s) {
return x
}
return 0
}
func executeSuccessor(f: (String) -> Int, s: String) -> Int {
return f(s)+1
}
let f1 = stringCharactersCount
let f2 = stringToInt
executeSuccessor(f: f1, s: "5555") // 5
executeSuccessor(f: f2, s: "5555") // 5556
Swift同時(shí)允許你定義一個(gè)函數(shù)參數(shù)的默認(rèn)值瓜喇。
func myFunction(someInt: Int = 5) {
// If no arguments are passed, the value of someInt is 5
}
myFunction(6) // someInt is 6
myFunction() // someInt is 5
Do關(guān)鍵字
do關(guān)鍵字允許你進(jìn)入一個(gè)新的范圍。
let a = "Yes"
do {
let a = "No"
print(a) // No
}
print(a) // Yes
do關(guān)鍵字同時(shí)允許包含一個(gè)或者多個(gè)catch分句歉糜。
do {
try expression
statements
} catch pattern 1 {
statements
} catch pattern 2 where condition {
statements
}