作者:李宁
出版社:信息技术第一出版分社
格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT
Swift权威指南试读:
前言
为什么要写这本书
由于苹果公司一直以来以生产硬件闻名,在2014年的WWDC上竟然发布了一种新的编程语言—— Swift。这一举动引起了业界不小的震动。在不到1 个月的时间里,Swift 就挤进流行语言前列,这在以前从未发生过。
Swift目前可用于开发iOS和OS X 平台的应用和游戏程序。但由于Swift刚诞生不久,中文资料还不多,而且由于 Swift 语言具有功能强大和效率开发高的特点,很有可能在将来取代Objective-C,成为iOS 和OS X平台上的主流开发语言。所以,为了让国内广大程序员能尽早掌握Swift开发技术,特意撰写了本书,以便可以让更多的人对Swift语言有所了解,更希望让更多的人成为国内乃至世界上第一批Swift语言专家。
本书的内容
Swift语言基础部分(第1章~第17章)主要介绍了Swift语言的基本语法,尤其是和其他语言不同的地方。项目实战部分(第18章~第20章)主要介绍了如何使用Swift语言开发iOS平台的应用和游戏,在最后一章还给出了一个Flappybird游戏以供大家学习Swift项目开发的全过程。
本书适合我吗
当您走进书店,看到书的标题中熟悉的字眼“Swift”,想了解这本书是否适合自己时,下面的提示对您的选购很有帮助:
● 您听说过iOS吗?
● 您知道App Store吗?
● 您听说过擅长做硬件的苹果公司居然推出了Swift开发语言了吗?
如果上述问题中有一个以上是肯定的,可以很高兴地告诉您,拿在手中的这本书确实是这个方向上的,下面需要进一步确认:
● 您对软件开发有经验或者有兴趣吗?
● 您对开发语言有了解吗?
● 您做过手机应用开发吗?
● 您是iOS或移动开发爱好者吗?
如果上述问题,您的回答中有肯定的,那么您已经具备了阅读本书需要的基础,不用担心读不懂了,那么:
● 您想快速了解并进入Swift应用开发吗?
● 您想找到一本系统介绍Swift开发的参考资料吗?
● 您想选择一本有原理剖析又有真实例子演示的教材吗?
● 您想选一本通俗易懂,符合自己阅读习惯的图书吗?
如上问题中,如果您有大多数回答都是肯定的,那么非常恭喜您,现在拿着的这本书差不多正是您需要的,可以放心地带回去开始自己的Swift之旅了。
如果还在犹豫,那么让下面几个提示告诉您,尽早开始学习的重要性:
● IT界中移动开发的热潮推动了移动互联网的快速发展,而Swift是一个非常强大的开发语言,其让您可以快速切入无线互联网领域;
● 在 App Store 发布应用的数量在快速增长,早日发布自己的 App 可以体现自己的开发价值和乐趣;
● 掌握了 Swift 开发就可以很快开发出供全球 iOS 用户使用的应用,有人已经在 App Store上赚到许多钱了!
本书的特点
● 国内第一本含金量超过Swift官方文档的原创图书。
● 第一本将Swift和最新的SpriteKit游戏引擎深度结合的原创图书。
● 实战性地讲解了Swift的开发技术和和技巧。
● 精彩游戏应用Flappybird让读者一览Swift项目开发全过程。
● 不仅介绍了Swift语言方面的知识,还结合了iOS应用和游戏开发进行讲解。尤其是讨论了基于SpriteKit的2D游戏开发技术。
● 推出了国内首套Swift视频课程:http://edu.51cto.com/course/course_id-1387.html。
● 随时提供答疑和完整资源下载:http://blog.csdn.net/nokiaguy。□ 从事iOS平台应用和游戏开发的程序员。
读者对象
□ 从事iOS平台应用和游戏开发的程序员。
□ 对Swift语言感兴趣的程序员。
□ 以前使用Objective-C,但想摆脱Objective-C繁琐的程序员。
□ 所有对新知识感兴趣的程序员。
源代码和工具下载
读者可以到作者的Blog:http://blog.csdn.net/nokiaguy下载相关的源程序和相关开发工具。
其他学习资源
由于目前Swift语言仍然是测试版,所以在读者拿到本书时,Swift的某些语法或API可能会有变化。为此,作者在51CTO上开了关于Swift的视频课程,这套教材会随着Swift的更新而不断更新。
视频地址:http://edu.51cto.com/course/course_id-1387.html。
勘误和支持
由于作者的水平有限,编写时间仓促,书中难免会出现一些错误或不准确的地方,恳请读者批评指正。如有问题或建议,请发送至 techcast@126.com 或在新浪微博(http://weibo.com/638012593)上留言。非常期待能够得到你们的真挚反馈。编辑联系邮箱为zhangtao@ptpress.com.cn。
致谢
感谢所有在本书写作过程中给予我指导、帮助和鼓励的朋友,尤其是人民邮电出版社的编辑,他们不仅对本书提出了宝贵的写作建议,而且还对本书进行了仔细的审阅。
感谢一直以来信任、鼓励、支持我的家人和朋友。
谨以此书献给我最亲爱的家人,以及众多热爱移动开发的朋友们!第1章未来的iOS开发语言Swift语言介绍
苹果(Apple)公司最近动作还是比较多的,除了即将推出的iWatch 等新硬件产品外,还推出了一种新的编程语言Swift。可能初次接触苹果软件开发的程序员对Swift还很陌生,当然,这也不奇怪,因为在写这本书时,Swift才刚刚推出。不过,由于Swift出身贵族,这也注定了Swift将拥有一个美好的未来,很可能成为苹果软件开发体系的中坚力量。既然Swift如此重要,作为求知欲极强的程序员们怎能放过这么一个成为国内,不!应该说世界上首批Swift专家的机会呢!现在就让我们开启Swift语言的开发之旅吧!
本章要点
□ Swift语言简介
□ Swift开发环境搭建
□ 创建Swift工程
□ 编写一段简单的Swift语言代码
□ 所见即所得的Playground1.1Swift语言的前世今生
在2014年的苹果WWDC大会上,最大的亮点当属Swift的出现了。因为苹果一贯以硬件为主,这次突然弄出了软件,而且还是生产软件的软件:Swift语言。自然会引起各方的广泛关注。国内外在 24 [1]小时内推出了大量关于Swift语言的学习资料,甚至视频 。我就从来没看过一种新技术被如此关注过,因为当年我赶上了微软C#的首发、还有Google的Go语言首发,关注度都没有Swift语言高,看来业界对这个一直玩硬件的苹果突然推出一种新编程语言还是很看好的。这么说当然是有证据的,就在Swift语言刚推出不到一个月的时间里,已经排到了编程语言的第16位,这在以前从未发生过。
既然说到Swift语言,那么就必须要提一下Swift的发明者Chris Lattner(可以叫他克里斯),Chris博士毕业,是一个全面发展的好学生。[2]
据说Chris最喜欢看的IT著作是龙书 ,还喜欢在旅游时带这本书。别人旅游时都看小说或看Video,这家伙却看编译原理的书,的确高大上。高手就是与别人不一样(就在写这本书时,我已经将龙、虎、鲸3本书的英文电子版放到平板电脑里了,准备旅游时看)。
下面主要来谈谈Chris的光荣事迹。Chris在硕士毕业时提出了一[3]套完整的运行时编译思想,奠定了LLVM 的发展基础。在博士期间继续领导LLVM编译框架向前发展,并取得了长足的进步。LLVM已经可以基于 GCC 前端编译器的语义分析结果进行编译优化和代码生成,所以,Chris在2005年毕业时已经是业界知名的编译器专家了。
苹果在2005年雇佣了Chris。Chris在苹果的几年中不仅大幅度优化和改进LLVM以适应Objective-C的语法变革和性能要求,同时发起了CLang项目,旨在全面替换GCC,现在这个目标已经实现了。从OS X 10.9和XCode 5开始,LLVM+GCC已经被替换成了LLVM+CLang。
在2010年,Chris接到了一个不同寻常的任务,就是为iOS和OS X平台开发下一代的编程语言,这就是现在看到的Swift。最初Swift完全是由Chris开发的。只是在一年后(2011年),才陆续有若干编译器专家加入了Swift团队。终于在4年后的2014年,Swift的第一个版本在苹果的2014年WWDC大会上向我们展示了她的魅力。1.2Swift到底是怎样的一种语言
Swift是一门博采众长的现代语言,在设计的过程中,Chris参考了Objective-C、Rust、Haskell、Ruby、Python、C#等优秀语言的特点,最终形成了目前Swift的语法特性。这也是为什么使用各种语言的程序员都能从Swift中找到自己熟悉的影子的原因。那么,Swift语言到底是一种怎样的语言。可以从下面几方面初步了解一下Swift语言。(1)Swift是面向对象的、编译型语言。编译时底层需要通过LLVM 生成本地代码才能执行,所以效率还是很高的。(2)Swift可以使用Cocoa和Cocoa Touch中的API。这也就意味着Swift与Objective-C一样,拥有了一个强大的Framework Library。(3)Swift吸取了很多编程语言的优点,同时Swift又具备了很多动态语言的语法特性和交互方式,当然,Swift本身是静态语言。所以,Swift尽可能地在静态语言和动态语言之间寻找平衡点。(4)既然说Swift是一种拥有动态特性的静态语言,那么Swift自然就是一门类型安全的语言。编译器可以在编译过程中检测出类型异常。例如,如果你期望为一个字符串变量赋值,那么类型安全机制会阻止你为这个变量设置整数。正是由于类型安全机制的存在,使开发者可以更早地发现并修复错误。(5)支持各种高级语言特性,包括闭包、泛型、面向对象、多返回值、类型接口、元组、集合等。[4](6)Swift能与Objective-C进行混合编程 ,但代码分属不同的文件。(7)全面支持Unicode编码。也就是说,可以用任何想用的字符作为变量名,例如,一个笑脸字符或汉字。图1-1就是使用笑脸图标和汉字作为变量名的一个典型例子。▲图1-1 使用笑脸图标和汉字作为变量名(8)使分号(;)变成了可选的符号。通常的静态语言,如Java、C#。每条语句结束后,都会在最后加上“;”,而Swift的每条语句不需要加“;”,当然,加上也没问题。只有在两条或多条语句写在同一行时才必须加“;”。(9)简化和增强了集合数据类型。用过Java和C#的读者知道。在这两种语言中,各种集合类型不可谓不全,但太多也有它不好的地方,就是不知道使用哪个。而且这些集合数据类型的功能也不够强大。在Swift语言中只提供了数组(Array)和字典(Dictionary)两个集合数据类型。其中Array类似List的功能,可以修改、添加、替换和删除数组元素。Dictionary类似Map的功能,用于存储Key-Value 风格的值。(10)Swift可以通过元组实现函数返回多个值。这一功能在其他语言中需要通过返回一个对象或结构体(指针)来实现。(11)提供了优雅的闭包解决方案。例如,在排序函数 sort 中可以将函数作为参数值传递。下面的代码是一种典型的写法:
let array1 = ["X", "A", "1", "2", "Z"]
func backwards(s1: String, s2: String) -> Bool
{
return s1 > s2
}
var array2 = sort(array1, backwards)
当然,更简洁的写法是var array2 = sort(["X", "A", "1", "2", "Z"] ) { $0 > $1 },如果读者不明白这么写是什么意思,那么就继续往后看吧!(12)Swift语言中提供了一种可选变量(Optional)。主要是为了应对一个变量可能存在,也可以是 nil 的情况。例如,将一个字符串(String)转换为整数(Int),但这个字符串是否可以成功转换为整数呢?如果不确定,就返回一个可选变量。如果成功转换,则返回正常的整数值;如果转换失败,则返回nil。实现的代码如下:
let str = "126CB5"
let value = str.toInt() // value是一个可选常量(用let声明是常量,用var声明是变量)
这时,value就是一个可选变量。要想判断转换是否成功,可以使用下面的代码:
if value
{
// 如果value是可选变量,引用时需要加上“!”,
// 表示该选项变量中肯定有一个值
println(value!)
}
可选变量的引入解决了大部分需要显式处理的异常,这部分工作也扔给编译器去做了。(13)拥有不同意义的nil。在Swift中的nil和Objective-C中的nil不同。在Objective-C中,nil是指向不存在对象的指针,而在Swift里,nil不是指针,它表示特定类型的值不存在。所有类型的可选值都可以被设置为nil,不仅是对象类型。(14)Swift中没有从语言层面支持异步和多核,不过可以直接在Swift中复用GCD(Grand Central Dispatch)的API实现异步功能。(15)Swift没有一部处理机制。可能是认为有了可选变量,异常会很少使用,所以未加入异常处理。1.3Swift开发环境搭建
尽管Swift语言拥有独立的编译器,不过,目前Apple并没有单独发布Swift开发包。所以只能连同XCode 6一起安装来使用Swift语言。由于XCode 6仍然是Beta版,所以,Apple并未对所有的人开放下载[5]XCode 6,只有拥有苹果开发者账号 的用户才允许下载XCode 6 Beta版。如果读者不舍得那99美金也不要紧,我已经将XCode 6 Beta的安装文件上传到的网盘,下载地址是http://pan.baidu.com/s/1hq7mAOk,下载后是一个dmg文件(2.33G左右),直接在Mac OS X下双击安装即可。XCode 6是可以和Xcode 5或其他版本共存的,所以不必担心,尽管安装。
安装完后,在 Mac的“应用程序”列表中多了一个“Xcode6-Beta.app”,直接双击运行即可。成功运行后,点击XCode6中的“Xcode”>“About Xcode”菜单项,如果能看到如图1-2 所示的窗口,并且 Version 显示的是 6.0,则说明 XCode6 已经安装成功了。▲图1-2 XCode 6的About 窗口1.4创建Swift工程(OS X和iOS平台)
Swift 语言可以开发 iOS 和 OS X 两个平台的程序,读者可以选择自己喜欢的平台学习Swift语言。如果有苹果开发者账号的,最好选择iOS平台,因为可以在iPhone上测试全部的功能。如果没有开发者账号,可以考虑选择OS X 平台,否则就只能在iOS模拟器上测试Swift 程序了。不管是创建哪个类型的工程,首先需要点击“File”>“New”>“Project”菜单项打开如图1-3所示的工程模板选择窗口。▲图1-3 创建 iOS 工程
如果选择iOS平台,通常选择“Application”,然后在右侧工程模板列表中选择一个,如“Single View Application”,如 图1-3所示。
如果读者选择 OS X 平台,可以选择“Application”,并在右侧的工程模板列表中选择“Command Line Tool”(一个终端工程模板),如图1-4所示。
接下来可以点击“Next”按钮进入下一步的设置。在下一步中需要输入工程名和工程支持的语言(为了测试方便,这里选择了OS X 平台,等涉及iOS 部分时,再创建iOS 工程)。当然,我们需要选择“Swift”,如图1-5所示,然后点击“Next”按钮进入下一步。在下一步中需要选择一个用于存放工程的目录,选择完成后,点击“Create”按钮,就会创建一个OS X工程。▲图1-4 创建Mac工程▲图1-5 建立 iOS工程,选择 Swift 语言
图1-5是OS X 工程的机构,其中新创建了一个main.swift文件。该文件用于输入Swift语言的代码。
在main.swift文件中默认生成了如下的代码:
import Foundation
println("Hello, World!")
直接运行该工程,就会在输出视图中输出“Hello, World!”。
如果读者要建立 iOS for Swift 工程,这里假设选择了图1-3 所示的“Single View Application”模板,在下一个设置页面输入工程名(如 first_swift_ios)后再进入下一个设置页面,选择存储目录后可创建iOS工程,工程结构如图1-7所示。▲图1-6 OS X 工程结构▲图1-7 iOS 工程结构
如果运行这个工程,首先会启动iOS模拟器(要选择iOS8模拟器),然后在模拟器中会运行一个 iOS 程序,该程序并没有任何 UI,背景为白色。本书后面的章节会介绍如何使用Swift开发iOS应用和游戏。
对于只想学习一下Swift语言的读者,建议还是使用OS X终端程序为好,因为OS X终端程序运行快速简单,可以排除其他的干扰。1.5瞧一瞧Swift到底长啥样
可能很多读者看到前面的介绍后跃跃欲试,想试一试 Swift 语言,不过先别忙,在正式编写Swift语言之前,先了解一下Swift语言的语法和样式是非常必要的。就像搞对象,起码得先看看对方长啥样,然后才能进行下一步。现在就让我们看看Swift到底长啥样。
Swift 语言和其他语言(如 Java、C#、Objective-C)类似,也支持一些常规的操作和语法元素,例如,运算符(+、−、*、/、%、++、&&、||等)、数据类型(字符串、数值等)、控制语句(if、switch、for)、类、方法(函数)等。不过 Swift 添加了很多特有的语法元素(至少是大多数语言都不具备的技术),例如,类扩展、增强的switch语句、小标、元组类型、返回多种的方法(函数)等。下面是一段标准的Swift语言代码,尽管没有枚举Swift中所有的新特性,但足够让我们充分了解 Swift 语言的基本语法规则。如果读者对某些表达式不理解也没关系,在后面的章节会深入介绍这些特有的语法规则。
import Foundation
var value1 = 20 // 定义并初始化一个整型变量
value1 += 35
// 输出:value1=55
println("value1=\(value1)")
let value2 = 42 // 定义并初始化一个整型常量
// 输出:97
println(value1 + value2)
// 定义并初始化一个数组变量
var array1 = ["abc","bbb","ccc"]
// 枚举数组中的每一个元素值
// 输出:abc bbb ccc
for element in array1
{
print(element + " ")
}
// 定义函数,返回值类型是String
func getPerson(name: String, age:Int) -> (String)
{
return "name:" + name + " age:" + toString(age)
}
println()
// 调用getPerson函数
let person = getPerson("bill", 50)
// 输出:person:name:bill age:50
println("person:\(person)")
// 定义一个可以返回多个值的函数(返回两个值:name和price)
func getProduct() -> (name:String, price:Float)
{
return ("iPhone6", 6666.66)
}
// 输出:(iPhone6, 6666.66015625)
// 调用getProduct函数,并输出其返回值
println(getProduct())
// 输出:product name: iPhone6
// 输出getProduct函数返回name值
println("product name: \(getProduct().name)")
// 定义Country类
class Country
{
var name = "China"
let area: Float = 960
// 定义一个成员方法
func getDescription() -> String {
return "Country:\(name) Area:\(area)"
}
}
// 创建一个Country类型的常量
let country = Country()
// 输出:Country:China Area:960.0
// 调用Country.getDescritpion方法,并输出该方法的返回值
println(country.getDescription())
// 定义一个类扩展,相当于将一个类的某一部分拿出来单独定义
extension Country
{
// 为Country类添加一个方法
func getAddress() -> (planet: String, location:String)
{
return ("Earth","Asia")
}
}
// 输出:Planet:Earth
// 调用扩展方法getAddress,并输出返回值中的planet
println("Planet:\(country.getAddress().planet)")
// 输出:Location:Asia
// 调用扩展方法getAddress,并输出返回值中的location
println("Location:\(country.getAddress().location)")
如果执行上面这段代码,会输出如下的信息。
value1=55
97
abc bbb ccc
person:name:bill age:50
(iPhone6,6666.66015625)
productname: iPhone6
Country:China Area:960.0
Planet:Earth
Location:Asia1.6所见即所得的Playground
XCode 6新增加了一个Playground,在iOS和OS X工程中都可以使用Playground。这个东西其实就是一个所见即所得的写代码的文件。这里的所见即所得就是编写代码后,不需要运行,立刻会显示出结果,并且还可以显示出代码中某个变量/常量的当前值。Playground比较适合于测试Swift语言的代码。但Playground在输出结果时可能会有些慢,而且写代码时会有些迟钝。这可能是因为需要实时解释Swift代码的原因!
要想使用 Playground,需要先创建 Swift 工程(iOS 和 OS X 工程都可以),然后在当前工程中点击“File”>“New”>“File”菜单项,会弹出一个如图1-8所示的窗口。在“iOS”和“OS X”中都有一个“source”节点,在该节点中都有一个“Playground”模板。不管是什么工程,选择哪个“source”节点下的“Playground”都可以。▲图1-8 选择“Playground”模板
选择“Playground”模板后,进入下一个设置页面。在该设置页面中需要选择playground文件的存储目录,通常和 Swift 文件放在同一个目录中。如果下方的“Targets”列表中的工程未选择,需要选择该工程,效果如图1-9所示。
如果成功创建了Playground文件,在工程目录中会多了一个文件扩展名为“playground”的文件。默认是 MyPlayground.playground。如果读者将上一节的代码都复制到MyPlayground.playground文件中,就会在代码右侧输出相应的结果,并且在输出结果和代码之间的部分还会显示当前变量/常量的当前值,效果如图1-10所示。▲图1-9 创建 Playground 文件▲图1-10 Playground 的效果1.7小结
相信看完本章后,读者已经对 Swift 语言有了一个大致的了解。也学会了如何搭建实验环境。不过真正的Swift开发之旅才刚刚开始。后面还有Swift的语法、内置函数、iOS应用程序开发、基于SpriteKit游戏引擎的游戏程序开发等知识要学习。下面就让我们整装待发,去欣赏Swift给我们的一次又一次震撼吧!
注 释
[1]. 为了赶上时代的脉搏,我也在24小时内推出了Swift的学习视频。感兴趣的读者可以关注http://edu.51cto.com/course/course_id-1387.html
[2]. 不知道龙书是什么东东的读者自己上网查。总之,有位古人说得好:精通龙、虎、鲸,玩转编译器。也想像Chris一样发明编程语言的朋友赶紧囤这3本书!
[3]. LLVM 是一套架构编译器(Compiler)的框架系统,用C++编写而成。提供了在编译、连接和运行期间的优化处理,并可以生成相应的汇编代码。目前支持ActionScript、Ada、D、Fortran、GLSL、Haskell、Java bytecode、C#、Objective-C、Python、Ruby、Rust、Scala等语言。著名的跨平台2D/3D游戏引擎libgdx(主要使用Java语言开发)在底层正因为使用了LLVM,才可以开发iOS平台的游戏。
[4]. 这一点与Objective-C 和C++的混合编程不同。这两种语言的混合编程,代码可以混合放在同一个文件中(.mm)。
[5]. 苹果开发者账号 99$/年。现在可以使用支付宝付款,大概一年 600 多人民币,感兴趣的读者可以到苹果官网去购买。因为只有拥有苹果开发者账号,才允许在iPhone、iPad设备上运行程序,并且可以下载任何处于Beta版本的开放工具(包括XCode6)。第2章千里之行始于足下——Swift语言基础
为了能够使读者更快地上手Swift编程。本章挑选了Swift语言的最基本特性加以介绍。尽管这些特性只占Swift全部特性的很少一部分,但却是所有的Swift程序都必不可少的。所以,读者通过对本章学习,可以使用Swift编写最基本的程序,并对Swift提供的新特性深深地震撼。
本章要点
□ Swift中的分号
□ 变量和常量
□ 常用的数据类型
□ 字符和字符串的常用操作
□ 元组类型
□ 可选类型
□ 注释2.1Swift语句和分号
通常来讲,学习一种计算机语言会从Hello World开始。也就是在终端或窗口上输出一行“Hello World”字符串,当然,输出什么都可以,这只是为了练习而已。不过在编写这行代码之前,首先要了解这种编程语言的语句是怎样写的。例如,用Java的语句规则去写Ruby代码,很有可能会出错。
Swift 语言编程格式总体来说中规中矩。不过,关键就在这个分号上。在 Java、C#这样的静态语言中,每条语句必须以分号(;)结尾。也就是说,在这些语言中,每条语句中的分号是可选的。但对于很多动态语言(如Ruby、Python等),如果每一条语句单独占用一行,并不需要加分号,而只有多条语句写在同一行时,才需要加分号。Swift语言吸取了动态语言的这个特性,将分号变成了可选的。例如,下面的 Swift语句都是合法的。
varid = 30
var product_var = "iPad5"; let xyz = 543.12;
id = 123;product_var = "iPhone7"
从这几行代码可以看出,如果在同一行写多条语句,语句之间必须加分号。但多条语句的最后一条语句后面可以不加分号。如果一行只写一条语句,可以不加分号,当然,也可以加分号。不过可能有很多程序员习惯了 C、C++、Java、C#等语言的写法,总习惯在后面加分号。但这也无所谓,反正加一个分号也费不了多少事。2.2变量和常量
源代码文件:src/ch02/var_let/var_let/main.swift
没有变量,程序就像一滩死水,没有活力。有了变量,程序才能千变万化,丰富多彩。所以,在编写大量Swift代码之前,先来了解一下Swift是如何定义变量的。在某些情况下,只允许变量设置一次值,然后再也不允许修改了,这种特殊的变量被称为常量。所以,在本节将着重介绍变量和常量。2.2.1 定义和初始化
不管是什么语言,变量都必须确定数据类型,否则是没法存储数据。但不同的语言,获取数据类型的方式是有区别的。例如,对于静态语言(Java、C#等),必须在定义变量时指定其数据类型。当然,为了让这个变量什么类型的值都能存储,也可以将变量类型设为Object或相似的类型。但不管设为什么,类型是一定要指定一个的。所以,静态语言变量的数据类型是在编译时确定的。
对于动态语言,变量也必须要有一个数据类型,只是这个数据类型并不是在定义变量时指定的,而是在程序运行到为这变量第一次初始化的语句时才确定数据类型。所以,动态语言的变量数据类型是在程序运行时确定的,这也是为什么这种语言被称为动态语言的原因之一。
不过在 Swift 语言中,使用了第三种方式来确定变量的数据类型,这就是“静态定义,动态推导”。其中的“静态定义”就是说变量的数据类型是在编译时确定的。而“动态推导”则说明在定义变量时并不需要明确指定数据类型,而只需使用var定义变量即可,如果要定义常量,需要使用let。然后Swift编译器在编译代码时,会根据变量(常量)初始化时右侧的表达式推导当前变量(常量)的类型。要注意的是,这里的var和let与其他静态语言中的 Object是不一样的。var和 let最终是可以获知准确类型的,而Object只是利用多态技术来存取各种数据类型的值,Object本身是不会反应具体类型的相应特性的(如属性、方法等),除非进行强行转换。例如,下面使用 var 定义了一个id变量。
var id = 20
这行语句是和下面的语句等效的,也就是说,编译器最终会认为20是Int类型,所以,在编译完程序后,会自动将id设为Int类型。所以id拥有Int类型的一切特征。
var id:Int = 20 // Int是数据类型,如何定义数据类型会在本节后面介绍
说道这里,就引出了变量定义的第一个需要注意的地方,就是如果不指定变量的数据类型,该变量必须被初始化。也就是说下面的语句是不合法的。
var id // 不合法,必须初始化
但是,如果为变量指定了一个数据类型,则可以在定义变量时不初始化,例如,下面的语句是合法的。
var id:Int
对于常量来说,不管指定不指定数据类型,都必须进行初始化。例如,下面两条语句都是不合法的。
let const1 // 不合法,常量必须初始化
let const2:Int // 不合法,常量必须初始化
而要想定义一个常量,必须使用下面的形式。
let const3:Int = 20 // 合法的常量定义(指定数据类型)
let const3 = 20 // 合法的常量定义(不指定数据类型,动态推导)
注意
不管是变量,还是常量。一旦确定了数据值类型,是不能后期改变的。例如,下面的代码会抛出编译错误。
var value = "abc"
value = 20
这里的value已经确定了是字符串(String)类型,不能再次被定义为Int类型。
除此之外还要注意,如果变量或常量在定义时未指定数据类型,初始化什么值都可以。一旦指定了数据类型,必须初始化与数据类型相符的值。例如,下面的代码是错误的。
var value:String = 123 // 必须初始化字符串值
如果想使用一个var或let定义多个变量或常量,可以用逗号(,)分隔多个变量或常量。例如,下面定义的变量和常量都是合法的。
var v1 = "abc", v2:Float = 20.12,v3:Bool
let const1 = "xyz", const2:Double = 12.34;
注意
在大多数静态语言中,指定整数或浮点数,会确认默认的类型。例如,在Java语言中,如果直接写23,会认为23是int类型;如果要让23变成long类型,则需要使用23L。如果直接写23.12,编译器会认为23.12是double类型,如果要将23.12变成float类型,需要使用23.12f。而对于float v = 23.12;,Java编译器会认为是错误的,因为23.12是double,而不是float,正确的写法是float v = 23.12f;。而对于short value = 23;是正确的。因为Java 编译器会自动将23 转换为short 类型,但23必须在short 类型的范围内。这么做是因为在byte code 中byte、short、int 都是使用同一个指令,而float和double使用了不同的指令,所以浮点数没有自动转换(理论上是可以的,估计是某人比较懒,不想麻烦)。在Swift语言中,浮点数会自动转换,所以var v:Float = 20.12是没问题的。
在更深入介绍Swift语言之前,先抛出两个全局函数:print和println。这两个全局函数可以在任何地方使用。用于在终端输出指定的信息(与C语言中的printf函数类似)。其中print输出信息后不换行,要想换行,需要加上“\r\n”,而println函数在输出信息后直接换行。之所以要先介绍这两个函数,是因为在后面的章节会使用这两个函数输出用于演示 Swift 特性的信息。下面是使用这两个函数的简单形式。
var value = 34
let const1:String = "xyz"
println(value)
print(const1 + "\r\n")
在深入使用这两个函数时再详细介绍它们的使用方法。2.2.2 将变量和常量值插入字符串中
在很多情况下,需要将多个变量的值连接在一起,并插入一些其他的字符串。如果这些变量都是字符串类型,可以直接使用加号(+)连接这些变量值。但如果这些变量不是字符串类型,就需要使用全局函数toString将它们转换为字符串,然后才能使用加号连接。例如,下面代码中定义了1个变量和两个常量,分别为Int、String和Bool类型,现在要将这3个变量和常量的值进行连接,然后使用println函数输出连接的结果。
var productId = 20
let productName:String = "iMac"
let available:Bool = true
println("Product ID:" + toString(productId) + " Product Name:" + productName + " Available:" +toString(available));
执行这段代码后,会输出如下的结果。
Product ID:20 Product Name:iMac Available:true
我们可以看到,尽管通过加号连接可以达到我们的目的,但却使代码变得不易维护和理解。在Swift中提供了一种更好的方法来达到这个目的,就是将变量和常量直接嵌入字符串,这样会使代码看起来更整洁。嵌入变量或常量的格式如下。
\(变量名/常量名)
下面的代码使用这种嵌入变量/常量的方式重新实现了上面的需求。输出结果与前面的代码的输出结果完全相同。
let description = "Product ID:\(productId) Product Name:\(productName) Available:\(available)"
println(description)
注意
经过测试,发现Swift语言的代码在初始化变量或常量时,等号(=)两侧必须有空格,而且在使用加号(+)连接字符串时,两侧必须有空格,否则无法编译通过。例如,var id=12是不合法的,需要使用var id = 12才行。也就是说“id”、“=”和“12”之间要有空格,当然,制表符也可以。有这个现在可能是Swift编译器没有考虑到这种情况,也许还有其他原因。不过添加这个现在是完全不符合逻辑的,大多数语言都没有这个限制。也许当Swift正式版发布时会取消这个限制,大家在编写Swift代码时应注意这一点。2.2.3 变量和常量的命名规则
由于Swift采用了Unicode 编码,所以几乎可以采用任何自己喜欢的字符作为变量(常量)名。例如,图2-1所示的代码使用了中文和特殊字符(笑脸)作为变量和常量名。
执行图2-1所示的代码后,会输出如图2-2所示的内容。▲图2-1 使用中文和笑脸作为变量名和常量名▲图2-2 输出中文和笑脸变量的值
尽管 Swift 中的变量和常量名称可以使用大多数的字符,但仍然有如下几种字符不能包含在变量和常量名称中,或不能作为变量和常量名称。不能使用这些字符的原因主要是为了避免歧义。
□ 数学符号,例如,“+”、“-”、“*”、“/”等运算符号。
□ 箭头。
□ 保留字,如var、let、for、if等。不能作为变量或常量名称,但可以包含在变量和常量名称中。
□ 非法的Unicode字符。
□ 连线和制表符。
如果一定要使用保留字作为变量或常量名的话,需要使用反引号(`)将保留字括起来。例如,下面的代码使用了var作为变量名。
var 'var' = 3
println('var')
尽管使用保留字作为变量名和常量名是可行的,但并不建议这么做。2.2.4 为变量和常量指定数据类型
尽管 Swift 语言支持类型推导,但如果想为变量或常量指定一个数据类型,也不是不可以的。在前面给出的Swift代码中已经多次这么使用了。
Swift和C风格的语言(Java、C#、C++等)不同,需要在变量或常量的后面指定数据类型,而不是在前面。这一点和Pascal很像。变量(常量)和数据类型之间需要使用冒号(:)分隔,冒号两侧可以有空格(制表符),也可以没有空格。例如,下面是几行典型的为变量和常量指定数据类型的代码。
var id:Int = 20
let productName : String = "Mac mini"
var price: Float = 4688
一旦为变量或常量指定了数据类型,在初始化变量或常量时,就只能指定与数据类型一致的值,Swift编译器不会再进行类型推导。2.3数据类型
源代码文件:src/ch02/data_type/data_type/main.swift
Swift语言也和其他语言一样,提供了若干个数据类型可供我们使用。除了几乎任何语言都支持的整数类型、浮点类型、布尔类型、字符串类型等,还指出一些特殊的类型,如元组类型、可选类型。不管是什么数据类型,在 Swift 语言中,数据类型名称都是以大写字母开头,并不存在像Java一样的int、float等内嵌的数据类型。在本节将详细介绍这些数据类型的使用方法。2.3.1 整数类型
整型是编程语言中最常用的数据类型。在Swift语言中支持8、16、32、64位的整型。这4类整型的类型名称如下。
□ 8位整型:Int8。
□ 16位整型:Int16。
□ 32位整型:Int32。
□ 64位整型:Int64。
在Swift语言中不同的整型拥有不同的类型别名(会在后面详细介绍),这些类型别名如下。
□ Byte:8位整型(UInt8)。
□ SignedByte:8位整型(Int8)。
□ ShortFixed:16位整型(Int16)。
□ Int:32位整型(Int32)。
□ Fixed:32位整型(Int32)。
在实际使用中,可以使用这些类型别名代替相应的整型。例如,下面是使用这些类型和类型别名定义的一些变量和常量。
var value1:Byte = 20
var value2:SignedByte = 30
var value3:ShortFixed = 1234
let value4:Int = 200
let value5:Fixed = 12345
var value6:Int64 = 4433113567
注意
在初始化不同的整型时要注意整型的取值范围。例如,SignedByte 的取值范围是−128 至 127。如果超过了这个取值范围,将无法成功编译程序。例如,var value:Byte = 1234是不合法的。
Swift还提供了另外一套整型,这就是无符号类型。与前面相应的有符号整型对应的无符号整型如下。
□ 8位无符号整型:UInt8。
□ 16位无符号整型:UInt16。
□ 32位无符号整型:UInt32。
□ 64位无符号整型:UInt64。
关于无符号整型应该了解如下几点。
□ 无符号整型除了UInt外,并未定义其他的类型别名。也就是说,并没有像UByte这样的数据类型(至少目前没有)。
□ 无符号整型的最小值是0,不允许设置负数;否则无法成功编译。
每一个有符号整型和无符号整型都有其取值范围,也就是最大值和最小值。例如,Int8的取值范围是−128~127,UInt8的取值范围是0~255。对于取值范围更大的整型,我们也没有必要记。因为每一个整型都有min和max属性,用于获取当前类型的最大值和最小值。例如,下面的代码可以分别获取Int32的最小值和最大值。
let minIntValue = Int32.min;
let maxIntValue = Int32.max;
除此之外,在 Swift 语言中还定义了很多内置的变量,用于获取数值类型的最大值和最小值。例如,INT16_MAX用于获取Int16的最大值,INT16_MIN用于获取Int16的最小值。但有一些数值类型的这些变量并没有定义,估计是因为 Swift 语言目前还是测试版的原因,可能Swift正式版出来后会好一些。
注意
对于Int 类型比较特殊,该类型会随着当前OS X 系统支持的位数不同而不同。例如,如果在32位的OS X系统中,Int = Int32;如果在64位的OS X系统中,Int =Int64。2.3.2 数制转换
Swift语言中的类型可以表示为十进制、二进制、八进制和十六进制。默认是十进制,数值前面加“0b”为二进制,数值前加“0o”位八进制,数值前加“0x”为十六进制。例如,下面的几个常量分别用十进制、二进制、八进制和十六进制的数值进行了初始化,并输出了这些常量值。
let decimalInt = 20
let binaryInt = 0b1100 //相当于十进制的12
let octalInt = 0o21 // 相当于十进制的17
let hexInt = 0x11 //相当于十进制的17
println(binaryInt);
println(octalInt);
println(hexInt);
这段代码的输出结果如下。
12
17
17
从这一点可以看出,尽管初始化时使用的是二进制表示法,但仍然以十进制数值表示常量值。2.3.3 浮点类型
常用的浮点数分为单精度和双精度浮点数,数据类型名称分别是Float和Double。其中Double也可以用Float64代替。下面是一些声明为浮点类型的变量和常量。
var value1:Float = 30.12
var value2:Float64 = 12345.54
let value3:Double = 332211.452.3.4 数值的可读性
为了增强较大数值的可读性,Swift语言增加了下划线(_)来分隔数值中的数值。例如,如果看到1000000000,估计很少有人会立刻反映出是10亿。大多数人可能需要查0的个数来判断该数值的大小。但使用 1_000_000_000,大多数人(尤其是搞财务的)一眼就可以看出是10亿。
不管是整数,还是浮点数,都可以使用下划线来分割数字。例如,下面是几个使用下划线分隔的数值初始化的变量和常量。
let value1 = 12_000_000
let value2 = 1_000_000.000_000_1
var value3:Int = 1_00_000
要注意的是,下划线两侧的数字不一定是3个为一组。分隔一个或n个数字都可以,例如,1_0_0_0_0_1也是合法的数字,不过这样分隔就没意义了。2.3.5 数值类型之间的转换
数值转换分为如下几种形式。
□ 整数之间的转换。
□ 浮点数之间的转换。
□ 整数和浮点数之间的转换。
对于整数之间的转换,如果之间使用数值位常量或变量赋值,则会自动转换,当然,前提是数值不超过整型的取值范围。
var value1:Byte = 12
let value2:Int32 = 12
在这两行代码中,同样都是12。但Swift编译器会将第一个12看做是Byte类型的值,而将第二个12看做是Int32类型的值。
如果是一个整型变量(常量)为另一个整型变量(常量)赋值,[1]则需要强行转换。即使将Byte变量值赋给Int变量值也需要强行转换 。
var int_value1:Int = 100
var byte_value:Byte = Byte(int_value1)
var int_value2:Int = Int(byte_value)
从这几行代码可以看出,强行转换的语法格式如下。
类型名 (变量/常量名)
浮点数之间以及浮点数和整数之间的转换与整数之间的转换类似,同样需要类型强行转换。
var float_value:Float = 1.23
var double_value1:Double = 1.23
var double_value2:Double = Double(float_value)
var int_value:Int = Int(double_value1)
同样是1.23,第一个1.23被认为是Float类型,第二个1.23被认为是Double类型。而将float_value赋给double_value2时仍然需要类型的强行转换。
将浮点数转换为整数时,会采用舍去的方式。例如,1.23和1.99被转换为整数后的结果都是1。2.3.6 类型别名
Swift中的类型别名和C/C++中的typedef类似,就是为一个类型起一个更有意义的别名。例如,在前面已经介绍过多个类型别名,如Byte、SignedByte等。只是typedef和C/C++中定义变量的规则一样,类型写在前面,自定义的类型名写中后面。代码如下:
typedef int mytype; // C/C++中的类型定义,mytype是新类型
如果在Swift中定义类型别名(新类型),需要用到typealias关键字。typealias的语法格式如下。
typealias 类型别名 = 原始类型
下面的代码就是一个典型的类型别名的例子。其中NewType就是Int32的类型别名。也就是说,在定义变量或常量时,NewType和Int32是完全一样的。
typealias NewType = Int32
var new_value:NewType = 1232.3.7 布尔类型
布尔类型是Bool,用于进行逻辑判断。例如,if语句就是布尔类型最常用的地方。下面的代码定义了一个布尔类型的变量,然后通过if语句进行判断,如果布尔类型变量值为true,则会执行if语句中的部分,否则会执行else语句中的部分。
var isFile:Bool = true
if isFile
{
println("isFile is true");
}
如果改用布尔类型的地方用了其他数据类型,那么将会编译出错。例如,下面的if语句就无法编译通过。
let i = 20
if i // 无法编译通过,i不是Bool类型,是Int类型
{
println("i = \(i)");
}
正确的写法应该将 if后面的部分改成Bool类型的值,具体代码如下。
let i = 20
if i == 20 // i = 20的结果是Bool类型,所以可以成功编译
{
println("i = \(i)");
}2.4字符和字符串
源代码文件:src/ch02/char_string/char_string/main.swift
字符和字符串也是 Swift 语言中的两个重要类型,只是由于这两个数据类型较复杂,所以单独用一节详细讨论。2.4.1 字符类型的常量和变量
字符类型的值只能存储一个字符(Unicode字符),使用Character表示字符类型。Swift语言中的字符类型与大多数语言中的字符表示法不同。例如,在Java中,字符需要使用单引号(')括起来,而在Swift语言中,字符和字符串都要使用双引号(")括起来。
let charValue1:Character = "a"
var charValue2:Character = "上"
试读结束[说明:试读内容隐藏了图片]