Swift要点:从Objective-C开发者的角度看Swift
代码环境是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 a 有点用处,但是你也想让这个可以用于浮点数。你可以定义一个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.a var tempB = tempPair.b var tempEqual: Bool = tempPair.equal() println((tempA) (tempB) equal: (tempEqual)") let tempPair1 = Pair<Float>(a: 1.0,b: 1.0) var tempA1 = tempPair1.a var tempB1 = tempPair1.b var 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,5] let dictionary: Dictionary<String,Int> = [ 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: |