Objective-C 開發者對 Swift 亮點的點評
如果這周一你像我一樣,正在享受著keynote,很興奮地要去開始嘗試所有新的優美的API。然后當聽到講一門新的語言:Swift時,耳朵都豎起來了!Swift不是對Objective-C的擴展,而是一門全新的語言,這突然震撼到了你。也許你很激動?也許你很開心?也許你沒什么想法。
Swift確實已經改變了未來我們開發iOS和Mac上的應用的方式。這篇文章中,我概括了Swift語言的一些亮點,把他們和Objective-C中對應的功能進行了比較。
請注意這并不是一篇Swift入門指南。蘋果已經發布了一本講解Swift的很棒的書,我強烈建議你去閱讀一下。取而代之地是,這是一篇對一些值得關注和使用的特別酷的功能的討論。
類型
Swift給出的第一件重大的事情是類型推斷。使用類型推斷的語言,程序員不需要使用類型信息給變量作注釋。編譯器可以從給變量賦的值推斷出該變量的類型。例如,編譯器可以自動把下面這個值設置為String類型:
// automatically inferred var name1 = "Matt" // explicit typing (optional in this case) var name2:String = "Matt"
連同類型推斷一起,Swift還給出了類型安全。在Swift中,編譯器(除了少數特殊情況)知道一個對象的完整類型。這使得它能決定怎樣來編譯代碼,因為它有更多的信息隨手可用。
這與Objective-C存在明顯的不同,Objective-C本質上是非常動態的。在Objective-C中,編譯期間不會真正知道對象的類型。部分原因是你可以在運行時給已有的類添加方法,添加一個全新的類,甚至改變一個實例的類型。
讓我們來更詳細地看一下,考慮到下面的Objective-C語句:
Person *matt = [[Person alloc] initWithName:@"Matt Galloway"]; [matt sayHello];
當編譯器看見調用sayHello時,它會檢查在頭文件中是否聲明了這個方法,它會發現類型Person調用了sayHello。如果沒有一個Persong對象,就會發生錯誤,但是這就是編譯器所能做的全部了。通常這就足以來捕捉到你引入的bug的第一行了。它會捕捉到輸入錯誤。但是因為動態的特性,編譯器不知道sayHello是否將會在運行時改變或者一定會改變。例如,它可以是在協議中的一個可選方法。(還記得這些都可以用respondsToSelector:來檢查嗎?)。
因為缺乏強類型,所以當在Objective-C中調用方法時編譯器基本上不會太多的事來進行優化。處理動態派發的方法叫做objc_msgSend。我相信你在許多的回溯中已經看見了!在該函數中,會查找選擇器的實現,然后再跳轉。你不能不承認這增加了開銷和復雜性。
現在看一下在Swift中相同功能的代碼實現:
var matt = Person(name:"Matt Galloway") matt.sayHello()
在Swift中,編譯器知道更多關于類型的信息,這在任何的方法調用中都會起到作用。編譯器確切地知道sayHello()在何處被定義。正因如此,通過直接地跳轉到實現處而不是必須經過動態派發,編譯器可以優化調用的地址。在其他情況下,編譯器可以使用虛擬函數表風格派發,這也遠低于Objective-C中動態派發的開銷。這種類型的派發就是C++中使用的虛函數。
在Swift中編譯器更加的有用。它將幫助阻止不確定的類型導致的bug進入你的代碼庫。通過智能的優化,還能夠使你的代碼運行的更加快速。
泛型
Swift另一個重大的特性是泛型。如果你熟悉C++,你會想起像模板這樣的東西。因為Swift是明確類型的,所以你必須在聲明一個函數時傳遞確定的類型。但是有時一些功能對于多個不同的類型是一樣的。這種情況的例子就是是經常用到的一對數值構成的一個結構體類型。在Swift中對于整數可以像下面這么實現:
struct IntPair { let a: Int! let b: Int!init(a: Int, b: Int) { self.a = a self.b = b } func equal() -> Bool { return a == b }
}
let intPair = IntPair(a: 5, b: 10) intPair.a // 5 intPair.b // 10 intPair.equal() // false</pre>
稍微有用。但是現在你想讓這個類對于浮點數也適用。你可以定義FloatPair類,但是它會和上面的類非常相似。因此泛型出現了。無需再聲明一個全新的類,你只要簡單的像下面這樣做即可:
struct Pair<T: Equatable> { let a: T! let b: T!init(a: T, b: T) { self.a = a self.b = b } func equal() -> Bool { return a == b }
}
let pair = Pair(a: 5, b: 10) pair.a // 5 pair.b // 10 pair.equal() // false
let floatPair = Pair(a: 3.14159, b: 2.0) floatPair.a // 3.14159 floatPair.b // 2.0 floatPair.equal() // false</pre>
相當的有用!為什么你這次會想到這個特性似乎并不清楚,但是相信我:機會是無窮無盡的。你會很快開始明白在自己的代碼里何處會用到這些。
容器
你已經知道并愛上了NSArray,NSDictionary和與它們對應的類。那么,你現在將了解Swift中與其相對應的類。幸運地是,他們非常相似。下面是如何定義數組和字典:
let array = [1, 2, 3, 4] let dictionary = ["dog": 1, "elephant": 2]這對于你來說應該相當熟悉了。然而還是有一點不同。在Objective-C中,數組和字典可以包含任意你想要的類型。但是在Swift中,數組和字典是類型化的。并且是通過使用我們上面的朋友—泛型來類型化的!
上面兩個變量可以使用明確的類型重寫(不過請記住你實際上不需要這么做),如下:
let array: Array<Int> = [1, 2, 3, 4] let dictionary: Dictionary<String, Int> = ["dog": 1, "elephant": 2]請注意是如何用泛型來定義存儲在容器中的東西的。對于數組來說還有一種簡短的形式來表示,這種形式的可閱讀性更強一些,但是本質上還是一樣的東西:
let array: Int[] = [1, 2, 3, 4]現在請注意你不能向該數組里添加非Int類型的東西。這聽起來是一件糟糕的事情,但是它卻極其有用。你的API再也不用寫文檔來說明,一個方法返回的數組或者一個數組屬性存儲的是什么東西了。你可以給編譯器提供明確的信息,以便它能更智能進行錯誤檢查和之前提到的優化。
可變性
關于Swift中集合的一件比較有趣的事是它們的可變性。沒有與Array和Dictionary對應的“可變的”類型。取而代之地是,使用標準的let和var。對于那些還沒有閱讀這本書,或者根本沒有探索Swift的人們(我建議你去做,ASAP!),let用于聲明一個常量,var用于聲明一個變量,是的,變量!let類似于在C/C++/Objective-C中使用const。如果集合用let來聲明就表示它的長度是不可變的。也就是說,不能再向其中添加,或者從其中移除。如果你試一下,你會得到下面的錯誤:
let array = [1, 2, 3] array.append(4) // error: immutable value of type 'Array<Int>' only has mutating members named 'append'這同樣適用于字典。基于此,編譯器能推斷出集合是否為可變的,然后做適當的優化。例如,如果大小不能改變,那么存儲值的存儲器不必再分配空間給新值。因此對于不會改變的集合總是使用let修飾是一個好習慣。
字符串
Objective-C中的字符串眾所周知處理起來很讓人煩躁,即使像拼接多個不同值這樣簡單的事情都很枯燥乏味。例如下面:
Person *person = ...;NSMutableString *description = [[NSMutableString alloc] init]; [description appendFormat:@"%@ is %i years old.", person.name, person.age]; if (person.employer) { [description appendFormat:@" They work for %@.", person.employer]; } else { [description appendString:@" They are unemployed."]; }</pre>
這相當的枯燥乏味,并且包含了許多與數據處理無關的字符。同樣的事情在Swift中像下面這樣處理:
var description = "" description += "\(person.name) is \(person.age) years old." if person.employer { description += " They work for \(person.employer)." } else { description += " They are unemployed." }更加整潔!請注意這種用一個格式創建一個字符串更加整潔的方式,現在你可以使用+=創建字符串。不再需要可變的和不可變的字符串。
Swift的另一個非常棒的擴展是字符串比較。你很清楚在Objective-C中使用==來比較字符串是不正確的。取而代之地,你應該使用isEqualToString:方法。因為前者是指針比較。Swift移除了這個間接的標準,相反地讓你能夠直接使用==比較字符串。這也意味著字符串可以用于switch語句。下面一段內容會更加詳細的介紹。
最后一個好消息是Swift支持全部Unicode字符集。你可以在字符串中使用任何Unicode碼位,甚至是函數和變量的名字!如果你想要,現在你可以定義一個叫開源中國的變量。
原文鏈接: raywenderlich 翻譯: 伯樂在線 - shinancao
譯文鏈接: http://blog.jobbole.com/71250/本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!