Swift已經推出了一段時間了,今天來總結一下Swift與Objective-c(以下簡稱OC)的語法有哪些不同。
1.常量與變量:
在Swift中定義常量和變量很簡單,常量使用let關鍵字,變量使用var關鍵字。
?var numberOfRows = 30 let maxNumberOfRows = 100
const int count = 10; double price = 23.55; NSString *myMessage = @"Objective-C is not dead yet!";
et count = 10 // count會被識別為Int var price = 23.55 // price會被識別為Double var myMessage = "Swift is the future!" // myMessage會被識別為String
var myMessage : String = "Swift is the future!"
在OC中你需要在每一句的後面寫上“;”以表達結束,不然會報錯,在Swift中你不需要再寫分號了,當然你寫上也沒有問題。
var myMessage = "No semicolon is needed"
3.String
在Swift中字符串的類型是String,不論你定義的是常量字符串還是變量字符串。
?let dontModifyMe = "You cannot modify this string" var modifyMe = "You can modify this string"
在Swift中連接兩個字符串組成新字符串非常方便,使用“+”:
let firstMessage = "Swift is awesome. " let secondMessage= "What do you think?" var message = firstMessage + secondMessage println(message)
在OC中我們使用stringWithFormat方法:
NSString *firstMessage = @"Swift is awesome. "; NSString *secondMessage = @"What do you think?"; NSString *message = [NSString stringWithFormat:@"%@%@", firstMessage, secondMessage]; NSLog(@"%@", message);
?var string1 = "Hello" var string2 = "Hello"if string1 == string2 { println("Both are the same") }
4.Array數組數組的用法Swift和OC差不多,我們來看示例:
在OC中:
?NSArray *recipes = @[@"Egg Benedict", @"Mushroom Risotto", @"Full Breakfast", @"Hamburger", @"Ham and Egg Sandwich"];
在Swift中:?var recipes = ["Egg Benedict", "Mushroom Risotto", "Full Breakfast", "Hamburger", "Ham and Egg Sandwich"]
在OC中你可以向NSArray和NSMutableArray中插入任意類型的參數,但是在OC中只能插入相同的參數。和NSArray相似,Swift中的Array也有很多方法,比如count方法返回數組中的元素個數:
?var recipes : [String] = ["Egg Benedict", "Mushroom Risotto", "Full Breakfast", "Hamburger", "Ham and Egg Sandwich"]?var numberOfItems = recipes.count // recipes.count will return 5
在OC中你使用NSMutableArray中的方法addObject來增加數組中的元素,Swift中的方法更簡單,你可以使用“+=”,比如:recipes += ["Thai Shrimp Cake"]不過請注意這個方法是數組間的,如果一個單個元素要加入數組中請在元素外面增加[]。要取出或者替換數組中的元素,使用索引,這點跟OC中相同:
?var recipeItem = recipes[0] recipes[1] = "Cupcake"
在Swift中可以使用Range來表示范圍:比如recipes[1...3] = ["Cheese Cake", "Greek Salad", "Braised Beef Cheeks"]這裡替換的是recipes中的第二到第四個元素。5.Dictionary字典
字典是一種集合類型,由鍵值對組成,這一點和OC中的NSDictionary很類似,請看示例:
OC中:
?NSDictionary *companies = @{@"AAPL" : @"Apple Inc", @"GOOG" : @"Google Inc", @"AMZN" : @"Amazon.com, Inc", @"FB" : @"Facebook Inc"};
Swift中:?var companies = ["AAPL" : "Apple Inc", "GOOG" : "Google Inc", "AMZN" : "Amazon.com, Inc", "FB" : "Facebook Inc"]你也可以聲明它的字典類型:?var companies: Dictionary= ["AAPL" : "Apple Inc", "GOOG" : "Google Inc", "AMZN" : "Amazon.com, Inc", "FB" : "Facebook Inc"]
要遍歷一個字典,需要使用元組來保存每一次循環的字典中的信息:for (stockCode, name) in companies { println("\(stockCode) = \(name)") }
你也可以單獨遍歷字典中的鍵或者值:for stockCode in companies.keys { println("Stock code = \(stockCode)") } for name in companies.values { println("Company name = \(name)") }
如果想給字典添加新的鍵值對,那麼使用如下語句:companies["TWTR"] = "Twitter Inc"
6.Class類在OC中創建類的話,會得到兩個文件,一個接口文件(.h文件)和一個實現文件(.m文件)。
而在Swift中生成類只有一個文件.swift文件。
示例:
class Recipe { var name: String = "" var duration: Int = 10 var ingredients: [String] = ["egg"] }
在上面的示例中我們創建了一個Recipe類,裡面有三個屬性,並且都聲明了類型,做了初始化。在Swift中類在初始化的時候它的屬性必須都被初始化。如果你不想設置某個屬性的默認值的話,使用?把它加入可選鏈中:class Recipe { var name: String? var duration: Int = 10 var ingredients: [String]? }這樣當你創建一個類的實例的時候:var recipeItem = Recipe()
這些可選鏈中的屬性的初始值是nil。你可以給它們賦值:recipeItem.name = "Mushroom Risotto" recipeItem.duration = 30 recipeItem.ingredients = ["1 tbsp dried porcini mushrooms", "2 tbsp olive oil", "1 onion, chopped", "2 garlic cloves", "350g/12oz arborio rice", "1.2 litres/2 pints hot vegetable stock", "salt and pepper", "25g/1oz butter"]
類可以繼承父類和遵守協議,示例:OC中:
?@interface SimpleTableViewController : UIViewController
Swift中:class SimpleTableViewController : UIViewController, UITableViewDelegate, UITableViewDataSource
7.Methods方法Swift允許你在類、結構體和枚舉中創建方法。
下面是一個沒有參數和返回值的方法:
class TodoManager { func printWelcomeMessage() { println("Welcome to My ToDo List") } }
在OC中調用一個方法的格式如下:todoManager printWelcomeMessage];
在Swift中調用一個方法的格式如下:todoManager.printWelcomeMessage()
如果要建立一個帶參數和返回值的方法,格式如下:class TodoManager { func printWelcomeMessage(name:String) -> Int { println("Welcome to \(name)'s ToDo List") return 10 } }
"->"用來指示方法的返回值類型。你可以這樣調用上面的方法:
var todoManager = TodoManager() let numberOfTodoItem = todoManager.printWelcomeMessage("Simon") println(numberOfTodoItem)
8.Control Flow控制流Swift中的控制流和循環頗有C語言的風格。
8.1for循環
for循環使用 for - in的結構,並且可以和Range(...或者..<)配合使用:
for i in 0..<5 { println("index = \(i)") }
會在控制台輸出:index = 0
index = 1
index = 2
index = 3
index = 4
如果我們使用...這是個閉集合,結果會返回:
index = 0
index = 1
index = 2
index = 3
index = 4
index = 5
如果你想用c中的結構也是可以的:for var i = 0; i < 5; i++ { println("index = \(i)") }
只不過for後面不用寫括號了。
8.2 if-else結構和OC中很像,只不過Swift中更簡單一些,條件語句不需要寫在括號中:
var bookPrice = 1000; if bookPrice >= 999 { println("Hey, the book is expensive") } else { println("Okay, I can affort it") }
8.3 switch結構Switch中的switch結構擁有非常強大的功能。
示例:
switch recipeName { case "Egg Benedict": println("Let's cook!") case "Mushroom Risotto": println("Hmm... let me think about it") case "Hamburger": println("Love it!") default: } println("Anything else")
首先Swift中的switch中可以控制字符串,OC中的NSString是不能被switch控制的,在OC中要實現類似功能你只能使用if-else。另外你可以看到在每個case中我們都沒有寫break,在OC中你必須在每個case中寫break,否則在當前case結束後會進入下一個case,在Swift中當前case被執行後就會自動跳出switch,如果需要進入下一個case,添加fallthrough語句。
最後,switch的case中可以包含Range操作:
var speed = 50 switch speed { case 0: println("stop") case 0...40: println("slow") case 41...70: println("normal") case 71..<101: println("fast") default: println("not classified yet") }
9.Tuple元組元組類型在OC中是沒有的,它可以包含多種不同的數據類型,你可以把它用作方法的返回值,這樣就可以用一個元組來代替返回一個復雜的對象了。例如:
let company = ("AAPL", "Apple Inc", 93.5)
你可以把元組company中的值取出來,用法如下:let (stockCode, companyName, stockPrice) = company println("stock code = \(stockCode)") println("company name = \(companyName)") println("stock price = \(stockPrice)")
或者company.0、company.1這樣的方法也能取到值,更好的做法是在定義元組的時候給每個元素起個名字:let product = (id: "AP234", name: "iPhone 6", price: 599) println("id = \(product.id)") println("name = \(product.name)") println("price = USD\(product.price)")
下面是一個把元組作為返回類型的例子:class Store { func getProduct(number: Int) -> (id: String, name: String, price: Int) { var id = "IP435", name = "iMac", price = 1399 switch number { case 1: id = "AP234" name = "iPhone 6" price = 599 case 2: id = "PE645" name = "iPad Air" price = 499 default:break }return (id, name, price) } }
調用:let store = Store() let product = store.getProduct(2) println("id = \(product.id)") println("name = \(product.name)") println("price = USD\(product.price)")
10.Optional可選型10.1可選型
可選型通常用在變量之中,可選型的默認值是nil。如果你給一個非可選型的變量賦值nil會報錯:
?var message: String = "Swift is awesome!" // OK message = nil // compile-time error
當你的類中的屬性沒有全部初始化的時候會報錯:class Messenger { var message1: String = "Swift is awesome!" // OK var message2: String // compile-time error }
在OC中當你給變量賦值為nil或者沒有初始化屬性的時候,你是不會收到一個編譯時錯誤的:NSString *message = @"Objective-C will never die!"; message = nil; class Messenger { NSString *message1 = @"Objective will never die!"; NSString *message2;}
但這不代表你不可以在Swift使用沒有初始化的屬性,我們可以使用?來表示這是一個可選型的變量:class Messenger { var message1: String = "Swift is awesome!" // OK var message2: String? // OK }
10.2那麼我們為什麼要用可選型呢?Swift語言設計的時候有很多安全方面的考慮,可選型表示了Swift是一門類型安全的語言,從上面的例子中你可以看到Swift中的可選型會在編譯時就去檢查某些可能發生在運行時的錯誤。
考慮下面的OC中的方法:
- (NSString *)findStockCode:(NSString *)company { if ([company isEqualToString:@"Apple"]) { return @"AAPL"; } else if ([company isEqualToString:@"Google"]) { return @"GOOG"; } return nil; }
這個方法用來判斷輸入的字符串是不是Apple和Google,如果是其他的話返回nil。假設我們在類中定義這個方法,並且在類中使用它:
NSString *stockCode = [self findStockCode:@"Facebook"]; // nil is returned?NSString *text = @"Stock Code - "; NSString *message = [text stringByAppendingString:stockCode]; // runtime error NSLog(@"%@", message);
這段代碼是可以通過編譯的,但是會在運行時發生錯誤,原因就是方法中傳入FaceBook返回了nil。上面OC中的代碼我們在Swift中的話是這樣寫的:
func findStockCode(company: String) -> String? { if (company == "Apple") { return "AAPL" } else if (company == "Google") { return "GOOG" } return nil }var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " let message = text + stockCode // compile-time error println(message)
這段代碼不能通過編譯,可以避免運行時的錯誤了。顯而易見,可選型的應用可以提高代碼的質量。10.3解包可選型
在上面我們已經看到了可選型的用法,那麼我們如何判斷一個可選型的變量有值還是為nil呢?
示例:
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " if stockCode != nil { let message = text + stockCode! println(message) }
很像OC中的配對,我們使用if判斷語句來做可選型的空值判斷。一旦我們知道可選型肯定有值的時候,我們可以使用強制拆封(或者叫解包),也就是在變量名後面加一個感歎號來取得變量的值。如果我們忘記做空值判斷會怎樣?你進形了強制拆封所以不會發生編譯時錯誤
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " let message = text + stockCode! // runtime error
會發生運行時錯誤,錯誤提示:Can’t unwrap Optional.None
10.4可選綁定
除了強制拆封,可選綁定是一個更簡單更好的做法。你使用if - let結構的可選綁定來判斷一個變量是不是空值
示例:
var stockCode:String? = findStockCode("Facebook") let text = "Stock Code - " if let tempStockCode = stockCode { let message = text + tempStockCode println(message) }
if let的意思是如果stockCode有值,那麼解包它,並且把它賦給一個臨時變量tempStockCode,並且執行下面大括號中(條件塊)的代碼,否則跳過大括號中的代碼。因為tempStockCode是一個新的常量,你不必再使用!來獲取它的值。
你可以簡化這個過程:
let text = "Stock Code - " if var stockCode = findStockCode("Apple") { let message = text + stockCode println(message) }
我們把stockCode的定義放到if中,這裡stockCode不是可選型,所以在下面的大括號中也不用再使用!如果它是nil,那麼大括號中的代碼就不會執行。10.5可選鏈
我們有一個類Code,裡面有兩個屬性code和price,它們的類型是可選型。把上面示例中的stockCode方法的返回值由String改為返回一個Code類型。
class Stock { var code: String? var price: Double? } func findStockCode(company: String) -> Stock? { if (company == "Apple") { let aapl: Stock = Stock() aapl.code = "AAPL" aapl.price = 90.32 return aapl } else if (company == "Google") { let goog: Stock = Stock() goog.code = "GOOG" goog.price = 556.36 return goog } return nil }
現在我們計算買了100個蘋果需要多少錢:if let stock = findStockCode("Apple") { if let sharePrice = stock.price { let totalCost = sharePrice * 100 println(totalCost) } }
因為findStockCode的返回值是可選值,我們使用可選綁定來判斷,但是Stock的price屬性也是可選的,所以我們又用了一個可選綁定來判斷空值。上面的代碼運行沒有問題,不用if let我們有更簡單的辦法,你可以把上面的代碼改成可選鏈的操作,這個特性允許我們把多個可選類型用?連接,做法如下:
if let sharePrice = findStockCode("Apple")?.price { let totalCost = sharePrice * 100 println(totalCost) }