Swift要點:從Objective-C開發人員的角度看Swift

來源:互聯網
上載者:User

標籤:

代碼環境是Xcode6.3-Beta3.

Swift已經極大的改變了開發iOS應用的方式。本文中,我會列出Swift的幾個重點,並且和Objective-C一一做出對比。

注意,本文不是Swift的入門指導。蘋果發布了Swift Programming Language,強烈建議您讀一讀這本書。文本主要介紹Swift中比較酷炫的特性。

類型

Swift提供的第一個重大的改進是類型推斷。使用了類型推斷的程式設計語言,開發人員不需要在聲明中明確指定變數的類型。編譯器會自動探知要賦給變數的值的類型。比如下面的例子,編譯器會自動設定變數的類型為String:

// 類型推斷var str = "Hello World!"// 明確定義類型,這裡可以不這樣var swift: String = "Hello Swift"

和類型推斷一起帶來的是型別安全。在Swift中,編譯器(一般來說全部,但是在很少的情況下)知道一個類型的全部類型。這樣給編譯器一個選擇如何編譯代碼的機會,因為編譯器有足夠的資訊。

這承托出了Objective-C的一個非常動態本質。在Objective-C中,任何類型在編譯期間都是未知的。這也是為什麼你可以在運行時給已經存在的類添加方法,添加一個全新的類型,甚至於改變一個對象的類型。

看看Objective-C的代碼:

Person *man = [[Person alloc] init];[man sayHello];

當編譯器看到對方法sayHello的調用的時候,它就會檢查類型Person類的標頭檔中是否有一個叫做sayHello的方法。如果沒有就報錯。編譯器就只可以做這些。這確實可以你可能引入的最初簡單的bug:如拼字錯誤。但是,因為動態性,編譯器不可能知道sayHello方法是否會在運行改變、甚至是否存在。這可能是一個協議中得optional方法。比如(還記得那些使用respondsToSelector的檢查嗎)。

由於缺乏強型別, 在Objective-C中調用方法的時候編譯器幾乎不能做什麼最佳化。處理代碼動態分發的方法是:objc_msgSend。我確定你在很多的時候見過這個方法。在這個方法中,尋找selector並調用。你不能說這沒有增加複雜度。

再回頭看看Swift的實現:

var p = Person()p.sayHello()

在Swift中,編譯器在調用方法的時候知道類型的更多資訊。它準確的知道sayHell方法在哪裡定義的。因此,Swift可以在方法調用的時候直接調轉到方法定義的地方,而無需經過任何的動態分發過程。在其他的情況下,Swift也可以使用vtable風格的分發方式,比Objective-C的動態分發花費小得多了。這也是C++的虛方法使用的分發機制。

Swift的編譯器也非常的有用。可以排除細微的類型相關的bug。它也能使你的代碼啟動並執行更快。

泛型

Swift帶來的另一個很大的改變是泛型。如果你對C++很熟悉的花,那麼你可以把這些和C++的template做類比。因為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: 1, b: 1)println("\(intPair.a)" + "\(intPair.b)" + " equal: \(intPair,equal())")

Sort of useful. But now you want this to work for floating point numbers as well. You could define aFloatPair class, but that would look awfully similar. This is where generics come in. Instead of declaring a whole new class, you could simply do this:

有點用處,但是你也想讓這個可以用於浮點數。你可以定義一個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 tempPair = Pair<Int>(a: 1, b: 1)var tempA = tempPair.avar tempB = tempPair.bvar tempEqual: Bool = tempPair.equal()println("\(tempA) " + "\(tempB) " + "equal: \(tempEqual)")let tempPair1 = Pair<Float>(a: 1.0, b: 1.0)var tempA1 = tempPair1.avar tempB1 = tempPair1.bvar tempEqual1: Bool = tempPair.equal()println("\(tempA1) " + "\(tempB1) " + "equal: \(tempEqual1)")

請各位讀者原諒我用了這麼爛得命名方式啊。。。

非常有用!你可能不是很清楚你為什麼需要泛型,但是相信我會有很多時候你會用到。你很快會發現在哪裡可以使用這些代碼。

容器

也許你覺得NSArray和NSDictionary和對應的可變類型都已經很好用了。但是你需要學習對應的Swift容器。幸運的是,他們非常相似。如:

let array = [1, 2, 3, 4, 5]let dictionary = ["dog": 1, "elephant": 2]

這些對你來說已經非常熟悉了。瞅一眼就可以搞定的。在Objective-C中,數組和字典可hi包含你想要的任何類型。但是在Swift中數組和字典是強型別的。而且這些容器都是泛型型別的。

上面的兩個變數可以使用類型運算式來重寫(你不是必須要這麼做),比如:

let array: Array<Int> = [1, 2, 3, 4, 5]let dictionary: Dictionary<String, Int> = ["dog": 1, "elephant": 2]

Notice how generics are used to define what can be stored in the container. There is also a short form for these, which is slightly more readable, but essentially boils down to the same thing:

注意泛型是怎麼定義什麼可以放進容器中的。定義的方式也有簡短的方式的,可讀性更好。但是本質上來說是一樣的:

let array: [Int] = [1, 2, 3, 4, 5]let dictionary: [String, Int] = ["dog": 1, "elephant": 2]

注意,這個時候你無法給數組添加任何的不是Int類型的值。這看起來不好,但是非常有用。你不再需要在文檔中專門指明屬性返回的數組中存放的是什麼類型的值。編譯器會自動檢測錯誤並最佳化代碼的編譯。

可變性

Swift容器的一個有意思的地方是他們都是可變的(mutable)。array和dictionary沒有“mutable”的對應類型了。可變和不可變都由letvar關鍵字控制。let就是用來聲明一個常量的關鍵字,var是用來聲明一個變數的。let就像是C、C++或者Objective-C中得const關鍵字一樣。

The way this relates to collections is that collections declared using let cannot change size. That is, they cannot be appended to, or removed from. If you try to, then you get an error like so:

使用let聲明的集合不能再修改size,也就是不能再append或者remove。如果你這麼做了,就會報錯:

let array: [Int] = [1, 2, 3, 4, 5]array.append(33)//immutable value of type ‘[int]‘ only has mutating members named ‘append‘

字典也同樣使用這個規則。這允許編譯器推測出這一類型的集合并作出相應的最佳化。如果size不能修改,集合的儲存實現不再需要重新分配新的空間容納新的值。因此,經常使用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."];}

This is quite tedious and contains a lot of characters that are nothing to do with the data being manipulated. The same in Swift would look like this:

這樣的寫法非常的冗長,而且包含了與本次操作無關的其他字元。同樣的功能在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-case運算式中。更多相關請繼續收看下一節內容。

Swift的字串的另一個好東西是本地支援Unicode。你可以使用任意的Unicode字元,即使是在變數名和函數名中。如果你願意你可以聲明一個方法

Swift要點:從Objective-C開發人員的角度看Swift

相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.