如果这周一你和我一样,正坐下来享受keynote,兴奋的开始尝试所有全新的可爱的API。 然后你猛然听到谈论一种新语言时,你竖起了耳朵:Swift! 它深深震撼了你,因为这不是对Objective-C的扩展,而是一种完全全新的语言。 也许你很兴奋? 也许你很高兴? 也许你不知道该怎么想。
Swift肯定改变了我们将来编写iOS和Mac程序的方式。 在这篇文章中,我概述了Swift语言的一些亮点,将它们与Objective-C中的对应部分进行了对比。
注意这篇文章不是一个Swift入门指南。 苹果已经发布了一本很棒的书,我强烈建议阅读它。 相反,这里着重讨论swift中值得注意和玩的特别酷的地方!
类型
Swift提供的第一个巨大利器是类型推断。在使用类型推断的语言中,程序员不需要用类型信息注释变量。编译器会根据赋值的变量去推断它。例如,编译器可以自动将此变量设置为String:
//自动推断
var name1 =“Matt”
//显式类型(在这种情况下是可选的)
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类型。如果没有该方法则会报错,但这是它只能做到这些。这通常足以捕捉引用的第一行的bug。它能捕获类似代码书写错误的bug。但是因为动态本质,编译器不知道sayHello是否会在运行时改变,甚至是否必须存在。比如,它可以是协议上的可选方法。 (可以用responsesToSelector:来检查)。
由于缺乏强类型,在Objective-C中编译器在调用方法时几乎做不了什么做优化。处理动态分发的方法称为objc_msgSend。我相信你在许多回溯中都能看到这一点!在这个方法中,方法选择器的实现先查找然后跳转。这是一定会增加开销和复杂性的。
现在看看Swift中的相同的代码:
```
var matt = Person(name:“Matt Galloway”)
matt.sayHello()
```
在Swift中,编译器对所有方法调用中的类型都了解更多。它确切地知道sayHello()被定义的位置,因此可以通过直接跳转到实现替代动态分发来优化某些调用。其他情况下,它可以使用vtable样式分发,这样的开销远远小于Objective-C中的动态分发。这类似于C ++中的虚拟函数调用。
编译器在Swift中更能发作用。它能帮助阻止子类型相关的bug进入你的代码库,还能通过智能优化使代码运行更快。
###泛型
Swift的另一个巨大的特性是泛型。如果你熟悉C++,那么你可以认为这个就像模板。因为Swift对类型很严格,所以你必须声明一个方法能够接受某些类型的参数,但有时有些同一种方法应当兼容多个不同类型。
这种情况的一个例子是,您希望将一对值存储在一起,因为他们是经常被使用的结构体。对于蒸熟你可以在Swift中这样实现:
```
struct IntPair {
让a:Int!
让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
```
搞定!但现在你想要这个方法也适用于浮点数。你可以定义一个FloatPair类,但是她们非常相似。这时候泛型就该发挥作用了。不需要声明一个全新的类,你可以这样做:
```
struct Pair <T:Equatable> {
让a:T!
让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
```
很棒!现在你可能还不太清楚为什么你需要这个特性,但相信我:用到机会是数不清的。你很快就会看到自己在代码中用到这些。
###容器
你已经知道并喜欢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]
let dictionary:[String:Int] = [“dog”:1,“elephant”:2]
```
注意,您不能把非Int类型的内容添加到数组中。这听起来不怎么友好,但其实非常有用。API不再需要记录什么被存储在数组中,它由某个方法返回或存储在属性中。编译器可以立即获取这些信息,以便它可以更好地检查错误和优化。
###可变类型
Swift中集合的一个有趣之处在于它们的可变类型。数组和字典没有“可变”对应,而是使用标准let和var。对于那些还没有读过这本书,或者深入到Swift中的人(我建议你尽快去读!),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'
```
这同样适用于dictionary。这就允许编译器推断集合,并进行适当的优化。例如,大小不能改变,则存储这些值的存储器不需要为了适应新值被重新分配空间。因此,申请一个不可变的集合时应当使用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."];
}
```
这是相当冗长乏味的,并且包含了很多与被操作的数据无关的字符。在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代码点,甚至方法和变量名!只要你愿意甚至可以有一个方法叫💩(一坨屎!)!
另一个好消息是,现在有一个内置的方法来计算字符串的真实长度。当涉及到完整的Unicode范围时,字符串长度的计算是不重要的。因为有的字符超过1个字节,所以你不能只是说它是在UTF8中存储字符串的字节数。在Objective-C中,使用2字节对对来存储字符串,所以NSString通过计算UTF16的数量进行计算,但这在技术上不是正确的,因为一些Unicode代码点占用两个2字节对。
幸运的是,Swift有一个方便的方法来计算字符串中代码点的真实数量,是叫做countElements()的上层方法。你可以这样用:
```
var poos =“\ u {1f4a9} \ u {1f4a9}”
countElements(poos)// 2
```
但它仍然不适用于所有情况,它只是计算Unicode代码点的数量,不考虑改变其他字符的特殊代码点。例如,可以在先前的字符上放一个变音符号。这种情况下,countElements()将返回2,即使它看起来像只有1个字符。像这样:
```
var eUmlaut =“e \ u {0}”
countElements(eUmlaut)// 2
```
通过以上这些,相信你会同意Swift中的字符串是棒的!
###Switch语句
在Swift的简短介绍中,我想要提到的最后一件事是switch语句。相比较于Objective-C中的这部分,Swift中已经有了显着的改进。这非常有趣,因为基于Objective-C是C的严格超集,这些改变不可能加到Objective-C中。
第一个令人兴奋的功能是关于字符串的Switch。这可能是你之前想做却不能做的事情,要在Objective-C中“switch”字符串,你必须使用大量带有isEqualToString的if语句,就像这样:
```
if ([person.name isEqualToString:@"Matt Galloway"]) {
NSLog(@"Author of an interesting Swift article");
} else if ([person.name isEqualToString:@"Ray Wenderlich"]) {
NSLog(@"Has a great website");
} else if ([person.name isEqualToString:@"Tim Cook"]) {
NSLog(@"CEO of Apple Inc.");
} else {
NSLog(@"Someone else);
}
```
这要打很多字,可读性也不高。然而Swift中是这样:
```
switch person.name {
case "Matt Galloway":
println("Author of an interesting Swift article")
case "Ray Wenderlich":
println("Has a great website")
case "Tim Cook":
println("CEO of Apple Inc.")
default:
println("Someone else")
}
```
除了关于字符串的Switch,注意这里还有一些有趣的地方,没有break。这是因为Switch中的case不会再执行下一个,不会出现意外出错的情况!
准备好,下面的switch语句很可能会打击你!
```
switch i {
case 0, 1, 2:
println("Small")
case 3...7:
println("Medium")
case 8..<10:
println("Large")
case _ where i % 2 == 0:
println("Even")
case _ where i % 2 == 1:
println("Odd")
default:
break
}
```
这里出现了break。因为Switch需要是穷尽的,即需要能够处理所有情况。这种情况下,希望default不做任何事情,所以添加了一个断点来声明不应该发生任何事情。
下一个有趣的事情是你看到的...和.. <。这些是新的运算符,用于定义范围。前者,定义了直到并包括右边界的范围。后者定义了一个范围,直到不包括右边界。这些都非常有用。
最后一件事是定义case作为输入的计算。这种情况下,如果值不匹配从零到十的任何值,则打印“Even”(如果是偶数)和“Odd”(如果它是奇数)。神奇!
###未来发展
这里只是希望给你体验一下Swift语言和它的奇妙之处。 但还有更多! 阅读苹果的书和[其他](https://developer.apple.com/library/prerelease/ios/documentation/swift/conceptual/swift_programming_language/index.html)苹果[文档](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-XID_26),将帮助你学习这种新的语言。 你迟早要这么做的!
此外,如果你想了解更多关于Swift,请查看我们[三个Swift的新书](https://www.raywenderlich.com/?page_id=74805) - 涵盖你需要知道的关于Swift,iOS 8等等!
我们很想听听你对Swift语言的看法,或者如果你有令人兴奋的亮点。 请联系我!
[原文链接](https://www.raywenderlich.com/73997/swift-language-highlights) 本文为个人翻译,不用与任何商业用途,如需转载请与本人联系。