代码环境是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.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, 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的更多相关文章

  1. Swift 3.0首个开发者预览版将在5月12日释出

    Swift团队在博客中宣布Swift 3.0语言首个开发者预览版将于5月12日释出,正式版将在4-6周之后推出.开发者预览阶段并无确定的更新周期和计划,不过Swift团队称努力将其控 制在4-6周内. ...

  2. 【阿里云产品公测】以开发者角度看ACE服务『ACE应用构建指南』

    作者:阿里云用户mr_wid ,z)NKt#   @I6A9do   如果感觉该评测对您有所帮助, 欢迎投票给本文: UO<claV   RsfTUb)<   投票标题:  28.[阿里云 ...

  3. 【转】从开发者的角度看待各移动平台 ios/android/wp7/win8ost title

    T_T 这伪技术博客都快给写成Tron的读书笔记专栏了,这样可不行欸~ 如今正是移动平台的战国时期,厌烦了去讨论移动平台的未来,也无意于在HTML5和Native App之间纠结.本文只从开发者纯技术 ...

  4. iOS开发者知识普及,Swift 挑战 Objective-C,谁会笑到最后?

    前言: 目前全球共有超过 7 亿台 iPhone 处于活跃状态,全球约有2000万名 iOS 开发者,这造就了 iOS 作为全球第二大移动设备平台的状态. 虽然安卓系统的全球市场占有率超过 iOS 系 ...

  5. 从开发者的角度分析iOS应如何省电

    从开发者的角度分析iOS应如何省电 说明 网上关于iPhone如何省电的文章很多.但是基本没有讲原理.而在生活中,很多人在使用iPhone中有着明显的错误的省电习惯. 本文从iOS开发者的角度,对iO ...

  6. Git学习系列之Git的功能特性(从一般开发者的角度和主开发者的角度来剖析)

    不多说,直接上干货! Git的功能特性,从一般开发者和主开发者的角度来进行剖析. Git的功能特性: 从一般开发者的角度来看,Git有以下功能: 1.从服务器上克隆完整的Git仓库(包括代码和版本信息 ...

  7. Swift 枚举-从汇编角度看枚举内存结构

    一.基本使用 先看枚举的几种使用(暂不要问,看看是否都能看懂,待会会逐一讲解) 1.操作一 简单使用 //第一种方式 enum Direction { case east case west case ...

  8. 从强制解包看 Swift 的设计

    从强制解包看 Swift 的设计 不知道大家有没有发现,在一个 Objective-C 和 Swift 混编的 App 中,当把一个 OC 中的参数转到 Swift 时,Swift 会自动把这个变量进 ...

  9. 另一个角度看元宇宙与RPA:人工世界、平行员工与RPA

    另一个角度看元宇宙与RPA:人工世界.平行员工与RPA 从元宇宙到平行员工,人工世界推动的虚实分工利好RPA 机器人是铁打营盘人类是流水兵,未来元宇宙的虚实分工RPA机会巨大 文/王吉伟 元宇宙是平行 ...

随机推荐

  1. you boot volume has only 0 byte size

    懒人方法: uname -a 列出目前使用的内核 dpkg -l | grep linux-image 列出存在的linux内核 sudo apt-get purge linux-image-3.16 ...

  2. inline和inline-block的间隙问题

    我们在前端布局的时候,会偶尔发现,在具有inline/inline-block属性的元素间存在一小段间隙,网上有些文章说这个间隙是6px,但我觉得应该是一个空格的宽度. 这里以inline-block ...

  3. state介绍

    state是salt最核心的功能,通过预先定制好的sls(salt state file)文件对被控主机进行状态管理,支持包括程序包(pkg).文件(file).网络配置(network).系统服务( ...

  4. Dungeon Game (GRAPH - DP)

    QUESTION The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a ...

  5. 数据流滑动窗口平均值 · sliding window average from data stream

    [抄题]: 给出一串整数流和窗口大小,计算滑动窗口中所有整数的平均值. MovingAverage m = new MovingAverage(3); m.next(1) = 1 // 返回 1.00 ...

  6. Python学习day5作业

    目录 Python学习day5作业 ATM和购物商城 1. 程序说明 2. 基本流程图 3. 程序测试帐号 4. 程序结构: 5. 程序测试 title: Python学习day5作业 tags: p ...

  7. springmvc中Controller方法的返回值

    1.1 返回ModelAndView controller方法中定义ModelAndView对象并返回,对象中可添加model数据.指定view. 1.2 返回void 在controller方法形参 ...

  8. MVC扩展HtmlHelper,加入RadioButtonList、CheckBoxList、DropdownList

    代码: using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions ...

  9. ueditor使用注意

    问题1:后端配置项没有正常加载,上传插件不能正常使用! 我用的是开发版,1.4.3.3 .Net版 网上查了很多,后来发现只是配置的问题而已. 1.在根目录下:config.json 其中有Img上传 ...

  10. NPOI导入导出Excel数据

    代码: using NPOI.HSSF.UserModel; using NPOI.SS.UserModel; using NPOI.XSSF.UserModel; using System; usi ...