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 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字符,即使是在变量名和函数名中。如果你愿意你可以声明一个方法 (pile of poo!)

另一个字符串的好东西是一种内建的方法计算一个字符串的长度。当字符串全部都是Unicode字符的时候,计算字符串的长度就变得重要了。你不能只是说有多少个byte用于存放UTF8字符串了。因为有的字符一个byte是不够的。在Objective-C中,NSString通过UTF16的个数来计算字符串的长度,2个byte存放一个字符串。但是,有的Unicode字符一次需要用两个2个byte的组合,所以之前NSString的计算方式不再能正确的表明字符串中字符的个数。

Fortunately, Swift has a handy function to calculate the true number of code-points in a string. It uses the top level function called countElements(). You would use it like so:

幸运的是,Swift有一个很好用的方法可以计算字符串的字符个数。这需要用到一个全局的countElements()方法。使用方法:

var poos = "\u{1f4a9}\u{1f4a9}"
//countElements(poos) // 2
count(poos) // 2

在Swift1.2中使用count方法

如你所见,Swift的字符串真的是非常好用!

Switch表达式

本文的最后需要简单的介绍一下Swift的switch表达式。Swift的switch表达式对Objective-C的switch表达式进行了极大的升级。因为,不打破Objective-C这个C语言的超集的情况是不能有大的升级的。

The first exciting feature is switching on strings. This is something that you may have wanted to do before, but couldn’t. To “switch” on strings in Objective-C you had to use lots of if-statements withisEqualToString: like so:

第一个就是switch表达式可以使用字符串。这也许是你早就想要的一个功能。在Objective-C中你不得不使用很多的if-else表达式和isEqualToString方法,比如:

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上使用string以外,还有一些有意思的地方。swtich表达式中是没有break的。这是因为Swift的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的问题。

下一个有意思的地方是...和..<。这些新的操作符是用来定义range的。前面的而一个是包含右边的数字。后面的一个是不包含右边的数字。这非常有用。

接下来学习什么?

希望本文能让你对Swift语言让人兴奋的特性有一个认识。但是还有更多的东西需要学习。你可以看苹果的文档,这回帮助你更好的学习这个新的语言。如果你觉得翻译的又什么问题请点击这里查看原文。

 

 

 

欢迎加群互相学习,共同进步。QQ群:iOS: 58099570 | Android: 330987132 | Go:217696290 | Python:336880185 | 做人要厚道,转载请注明出处!http://www.cnblogs.com/sunshine-anycall/p/4344956.html

时间: 2024-10-02 02:24:38

Swift要点:从Objective-C开发者的角度看Swift的相关文章

swift初探(供objective c开发者参考)

6月初的wwdc苹果推出了一门新的开发语言swift.系统10.9.3以上安装xcode6 beta版即可体验swift. 苹果公司做了尽可能多的努力让这门语言迅速成为一个工业级的实用编程语言,而不是华而不实的花瓶. 通过xcode6查看文档,可以发现之前现存的接口都多了swift适配,举例如下(以下都从苹果官方文档中摘录): 简单方法适配: swift: func UIImageJPEGRepresentation(_ image: UIImage!,                     

从开发者角度看国内Android Market的用户体验

开发者角度看国内Android Market的用户体验-小程序 体验者 开发者"> 编者按:本文作者为丁香园CTO,贝塔咖啡联合创始人,冯大辉 近一段时间在发布 丁香园用药助手 Android 版的过程中把国内几个重要的 Android Market 用了个遍,每次要发布新版本的时候都要感慨一下:几乎所有的 Android Market 后台的用户体验都不怎么好. 信息各有一 国内所有的 Android Market 和 Google 官方 Android Market 都是不"

从多元化的角度看seo 才能真正落实站点的优化

  SEO现在进入了蓬勃发展的时期,上到大型站点,下到草根站长,越来越多的人都对SEO给予了足够的重视以及期望,希望靠着这个后起之秀让自己的站点在竞争激烈的网络时代,获得更多的优势.近期笔者参加了夫唯的培训,培训后不能说自己已经掌握所有的SEO优化技巧,但是最基本的什么该做,什么不该做还是有一定的分辨能力的.当大多数的人都认为优化其实是由内容和外链的建设模式,笔者认为大家的想法太局限了,从优化的操作上来看,一个站点的优化的确是建立在内容和外链,但SEO显然没有你所想的那样"低技术",一

抢先看 Swift 3.0

本文讲的是抢先看 Swift 3.0, 这篇文章介绍了 Swift 3.0 的目标.发布进程和预计的时间表. Swift 3.0 是一个不兼容 Swift 2.2 语法的大版本更新.它对语法和基本库有着根本性的改变.Swift 3.0 实现的完整修改列表可以在 Swift evolution site 中查看. Swift 3.0 是首个包含 Swift Package Manager 的发布版本.现在 Swift Package Manager 还处于早期开发版本,它支持开发和发布跨平台的 S

[重构 Swift 中单例的用法](Refactoring singleton usage in Swift)

本文讲的是[重构 Swift 中单例的用法](Refactoring singleton usage in Swift), 使代码库更加简洁.模块化.和可测试的技巧 2017 年 2 月 10 日 在软件开发中,单例模式有足够的原因被广泛的不推荐和不赞成.它们难以测试或者说是不可能测试,当它们在其他类中隐式调用时会使你的代码库混乱,让代码难以复用.大部分时候,一个单例其实就相当于一个伪全局变量.每个人都知道,至少知道这是一个糟糕的主意.然而,单例有时又是不可避免且必须的.我们如何能把它们用一种整

《Swift iOS应用开发实战》——1.1初识Swift

1.1初识Swift Swift是苹果在WWDC 2014所发布的一门编程语言,用于开发iOS和OS X应用程序. 2010年7月LLVM编译器的原作者暨苹果开发工具部门总监克里斯·拉特纳(Chris Lattner,就是在WWDC 2014大会上亲自演示Swift代码的那位仁兄)开始着手开发Swift语言,一直到2014年6月发布,Swift大约经历了4年的开发期.在WWDC 2014大会中,苹果宣称Swift的特点是:快速.现代.安全和具有交互性. Swift的处理速度非常快.在WWDC上,

从脚本编程的角度看JSP的安全

JSP作为建立动态网页的技术正在不断升温.JSP和ASP.PHP.工作机制不太一样.一般说来,JSP页面在执行时是编译式,而不是解释式的.首次调用JSP文件其实是执行一个编译为Servlet的过程.当浏览器向服务器请求这一个JSP文件的时候,服务器将检查自上次编译后JSP文件是否有改变,如果没有改变,就直接执行Servlet,而不用再重新编译,这样,效率便得到了明显提高. 今天我将和大家一起从脚本编程的角度看JSP的安全,那些诸如源码暴露类的安全隐患就不在这篇文章讨论范围之内了.写这篇文章的主要

从三个角度看上海园区招募网

由于没有实际了解asus生产流程及hr部门,所以以下分析仅从网络专业角度来看上海园区招募网,未能结合asus实际提出改进建议和发展目标(比如可以把上海园区招募网独立出来发展成电子行业的专业招聘网,一方面来服务asus另外也可以带来实际的收益.)<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> 一.从网站设计技术角度看上海园区招募网 1.上海园区招募网最好有自己独立的域名

王顺铨:站在消费者角度看互联网

主持人:首先给我们介绍一下您的个人经历,包括您这次参赛的网站. 王顺铨:因为我是学艺术类的,是中央工艺美院毕业的,一直做广告搞平面设计.在2005年开始进入互联网,在2006年通过自己的特长和专长,建了一个音乐网站,因为自己对音乐比较喜欢.当时发现互联网上高品质,高端的音乐比较少,当时就进入高端市场.现在百度搜索网络音乐相对来说比较,他的质量都比较低,对于拿高端MP3播放器的人就比较枯燥,我们就解决他这个问题.现在随着播放器空间的放大,他可以储存很大容量的文件,我们高品质音乐的网站,就是现阶段满