swift简介
2015-08-14 17:01
337 查看
概述
Swift是苹果2014年推出的全新的编程语言,它继承了C语言、ObjC的特性,且克服了C语言的兼容性问题。Swift发展过程中不仅保留了ObjC很多语法特性,它也借鉴了多种现代化语言的特点,在其中你可以看到C#、Java、Javascript、Python等多种语言的影子。同时在2015年的WWDC上苹果还宣布Swift的新版本Swift2.0,并宣布稍后Swift即将开源,除了支持iOS、OS X之外还将支持linux。本文将继续iOS开发系列教程,假设读者已经有了其他语言基础(强烈建议初学者从本系列第一章开始阅读,如果您希望从Swift学起,那么推荐你首先阅读苹果官方电子书《the swift programming language》),不会从零基础一点点剖析这门语言的语法,旨在帮助大家快速从ObjC快速过度到Swift开发中。即便如此,要尽可能全面的介绍Swift的语法特点也不是一件容易的事情,因此本文将采用较长的篇幅进行介绍。
基础部分
第一个Swift程序
数据类型
基础类型
集合类型
元组
可选类型
运算符
控制流
函数和闭包
函数
闭包
类
属性
方法
下标脚本
继承
协议
扩展
枚举和结构体
结构体
枚举
泛型
目 录
基础部分
第一个Swift程序
创建一个命令行程序如下:Swift没有main函数,从top level code的上方开始往下执行(就是第一个非声明语句开始执行[表达式或者控制结构,类、结构体、枚举和方法等属于声明语句]),不能存在多个top level code文件(否则编译器无法确定执行入口,事实上swift隐含一个main函数,这个main函数会设置并调用全局 “C_ARGC C_ARGV”并调用由top level code构成的top_level_code()函数);
Swift通过import引入其他类库(和Java比较像);
Swift语句不需要双引号结尾(尽管加上也不报错),除非一行包含多条语句(和Python有点类似);
数据类型
Swift包含了C和ObjC语言中的所有基础类型,Int整形,Float和Double浮点型,Bool布尔型,Character字符型,String字符串类型;当然还包括enum枚举、struct结构体构造类型;Array数组、Set集合、Dictionary字典集合类型;不仅如此还增加了高阶数据类型元组(Tuple),可选类型(Optinal)。基础类型
Xcode 从6.0开始加入了Playground代码测试,可以实时查看代码执行结果,下面使用Playground简单演示一下Swift的基础内容,对Swift有个简单的认识:Swift添加了类型推断,对于赋值的常量或者变量会自动推断其具体类型;
Swift是强类型语言(应该说它比C#、Java等强类型语言控制还要严格),不同的数据类型之间不能隐式转化,如果需要转化只能强制转化;
在Swift中类型转换直接通过其类型构造函数即可,降低了API的学习成本;
集合类型
Swift提供了三种集合类型:数组Array、集合Set、字典Dictionary。和ObjC不同的是,由于Swift的强类型,集合中的元素必须是同一类型,而不能像ObjC一样可以存储任何对象类型,并且注意Swift中的集合是值类型而非引用类型(事实上包括String、结构体struct、枚举enum都是值类型)。首先看一下Swift中的数组:
元组(Tuple)
在开发过程中有时候会希望临时组织一个数据类型,此时可以使用一个结构体或者类,但是由于这个类型并没有那么复杂,如果定义起来又比较麻烦,此时可以考虑使用元组。可选类型
所谓可选类型就是一个变量或常量可能有值也可能没有值则设置为可选类型。在ObjC中如果一个对象类型没有赋值,则默认为nil,同时nil类型也只能作为对象类型的默认值,对于类似于Int等基本类型则对应0这样的默认值。由于Swift是强类型语言,如果在声明变量或常量时没有进行赋值,Swift并不会默认设置初值(这一点和其他高级语言不太一样,例如C#虽然也有可选类型,但是要求并没有那么严格)。可选类型其本质就是此类型内部存储分为“Some”和“None”两个部分,如果有值则存储到“Some”中,没有值则为“None”(早期Playground中可以看到两个部分,如今已经取消显示Some等描述了),使用感叹号强制解包的过程就是取出“Some”部分;
既然可选类型有可能有值,也可能没有值那么往往有时候就需要判断。可以使用if直接判断一个可选类型是否为nil,这样一来就可以根据情况进行强制解包(从Some部分取出值的过程);另一个选择就是在判断的同时如果有值则将值赋值给一个临时变量或常量,否则不进入此条件语句,这个过程称之为“可选绑定”。
运算符
Swift中支持绝大多数C语言的运算符并改进以减少不必要的错误(例如等号赋值后不返回值),算术运算会检查溢出情况,必要时还能使用新增的溢出运算符。另外Swift中还可以对浮点数使用取余运算符,新增了区间运算符。对于基本的运算符这里不再一一介绍,简单看一下Swift中的区间运算符和溢出运算符。控制流
Swift中的多数控制流和其他语言差别并不大,例如for、while、do while、if、switch等,而且有些前面已经使用过(例如for in循环),这里将着重介绍一些不同点。函数和闭包
函数
函数是一个完成独立任务的代码块,Swift中的函数不仅可以像C语言中的函数一样作为函数的参数和返回值,而且还支持嵌套,并且有C#一样的函数参数默认值、可变参数等。闭包
Swift中的闭包其实就是一个函数代码块,它和ObjC中的Block及C#、Java中的lambda是类似的。闭包的特点就是可以捕获和存储上下文中的常量或者变量的引用,即使这些常量或者变量在原作用域已经被销毁了在代码块中仍然可以使用。事实上前面的全局函数和嵌套函数也是一种闭包,对于全局函数它不会捕获任何常量或者变量,而对于嵌套函数则可以捕获其所在函数的常量或者变量。通常我们说的闭包更多的指的是闭包表达式,也就是没有函数名称的代码块,因此也称为匿名闭包。在Swift中闭包表达式的定义形式如下:
{ ( parameters ) -> returnType in
statements
}
下面通过一个例子看一下如何通过闭包表达式来简化一个函数类型的参数,在下面的例子中闭包的形式也是一而再再而三的被简化,充分说明了Swift语法的简洁性:
类
作为一门面向对象语言,类当然是Swift中的一等类型。首先通过下面的例子让大家对Swift的class有一个简单的印象,在下面的例子中可以看到Swift中的属性、方法(包括构造方法和析构方法):Swift中的类不必须继承一个基类(但是ObjC通常必须继承于NSObject),如果一个类没有继承于任何其他类则这个类也称为“基类”;
Swift中的属性定义形式类似于其他语句中的成员变量(或称之为“实例变量”),尽管它有着成员变量没有的特性;
Swift中如果开发者没有自己编写构造方法那么默认会提供一个无参数构造方法(否则不会自动生成构造方法);
Swift中的析构方法没有括号和参数,并且不支持自行调用;
属性
Swift中的属性分为两种:存储属性(用于类、结构体)和计算属性(用于类、结构体、枚举),并且在Swift中并不强调成员变量的概念。 无论从概念上还是定义方式上来看存储属性更像其他语言中的成员变量,但是不同的是可以控制读写操作、通过属性监视器来属性的变化以及快速实现懒加载功能。计算属性并不直接存储一个值,而是提供getter来获取一个值,或者利用setter来间接设置其他属性;
lazy属性必须有初始值,必须是变量不能是常量(因为常量在构造完成之前就已经确定了值);
在构造方法之前存储属性必须有值,无论是变量属性(var修饰)还是常量属性(let修饰)这个值既可以在属性创建时指定也可以在构造方法内指定;
从上面的例子中不难区分存储属性和计算属性,计算属性通常会有一个setter、getter方法,如果要监视一个计算属性的变化在setter方法中即可办到(因为在setter方法中可以newValue或者自定义参数名),但是如果是存储属性就无法通过监视属性的变化过程了,因为在存储属性中是无法定义setter方法的。不过Swift为我们提供了另外两个方法来监视属性的变化那就是willSet和didSet,通常称之为“属性监视器”或“属性观察器”。
存储属性的默认值设置不会引起属性监视器的调用(另外在构造方法中赋值也不会引起属性监视器调用),只有在外部设置存储属性才会引起属性监视器调用;
存储属性的属性监视器willSet、didSet内可以直接访问属性,但是在计算属性的get、set方法中不能直接访问计算属性,否则会引起循环调用;
在didSet中可以修改属性的值,这个值将作为最终值(在willSet中无法修改);
方法
方法就是与某个特定类关联的函数,其用法和前面介绍的函数并无二致,但是和ObjC相比,ObjC中的函数必须是C语言,而方法则必须是ObjC。此外其他语言中方法通常存在于类中,但是Swift中的方法除了在类中使用还可以在结构体、枚举中使用。关于普通的方法这里不做过多赘述,用法和前面的函数区别也不大,这里主要看一下构造方法。构造方法的所有参数默认情况下既是外部参数又是局部参数;
Swift中的构造方法分为“指定构造方法”和“便利构造方法(convenience)”,指定构造方法是主要的构造方法,负责初始化所有存储属性,而便利构造方法是辅助构造方法,它通过调用指定构造方法并指定默认值的方式来简化多个构造方法的定义,但是在一个类中至少有一个指定构造方法。
下标脚本
下标脚本是一种访问集合的快捷方式,例如:var a:[string],我们经常使用a[0]、a[1]这种方式访问a中的元素,0和1在这里就是一个索引,通过这种方式访问或者设置集合中的元素在Swift中称之为“下标脚本”(类似于C#中的索引器)。从定义形式上通过“subscript”关键字来定义一个下标脚本,很像方法的定义,但是在实现上通过getter、setter实现读写又类似于属性。假设用Record表示一条记录,其中有多列,下面示例中演示了如何使用下标脚本访问并设置某一列的值。继承
和ObjC一样,Swift也是单继承的(可以实现多个协议,此时协议放在后面),子类可以调用父类的属性、方法,重写父类的方法,添加属性监视器,甚至可以将只读属性重写成读写属性。子类的指定构造方法必须调用父类构造方法,并确保调用发生在子类存储属性初始化之后。而且指定构造方法不能调用同一个类中的其他指定构造方法;
便利构造方法必须调用同一个类中的其他指定构造方法(可以是指定构造方法或者便利构造方法),不能直接调用父类构造方法(用以保证最终以指定构造方法结束);
如果父类仅有一个无参构造方法(不管是否包含便利构造方法),子类的构造方法默认就会自动调用父类的无参构造方法(这种情况下可以不用手动调用);
常量属性必须默认指定初始值或者在当前类的构造方法中初始化,不能在子类构造方法中初始化;
协议
协议是对实例行为的一种约束,和ObjC类似,在Swift中可以定义属性和方法(ObjC中之所以能定义属性是因为@property的本质就是setter、getter方法)。和其他语言不同的是Swift中的协议不仅限于类的实现,它同样可以应用于枚举、结构体(如果只想将一个协议应用于类,可以在定义协议时在后面添加class关键字来限制其应用范围)。Swift的协议中可以约定属性是实例属性还是类型属性、是读写属性还是只读属性,但是不能约束其是存储属性还是计算属性;
协议中的类型属性和类型方法使用static修饰而不是class(尽管对于类的实现中类型属性、类型方法使用class修饰);
协议中约定的方法支持可变参数,但是不支持默认参数;
协议中约定的构造方法,在实现时如果不是final类则必须使用require修饰(以保证子类如果需要自定义构造方法则必须覆盖父类实现的协议构造方法,如果子类不需要自定义构造方法则不必);
一个协议可以继承于另外一个或多个协议,一个类只能继承于一个类但可以实现多个协议;
协议本身就是一种类型,这也体现除了面向对象的多态特征,可以使用多个协议的合成来约束一个实例参数必须实现某几个协议;
扩展
Swift中的扩展就类似于ObjC中的分类(事实上在其他高级语言中更多的称之为扩展而非分类),但是它要比分类强大的多,它不仅可以扩展类还可以扩展协议、枚举、结构体,另外扩展也不局限于扩展方法(实例方法或者类型方法),还可以扩展便利构造方法、计算属性、下标脚本、枚举和结构体
结构体
结构体和类是构造复杂数据类型时常用的构造体,在其他高级语言中结构体相比于类要简单的多(在结构体内部仅仅能定义一些简单成员),但是在Swift中结构体和类的关系要紧密的多,这也是为什么将结构体放到后面来说的原因。Swift中的结构体可以定义属性、方法、下标脚本、构造方法,支持扩展,可以实现协议等等,很多类可以实现的功能结构体都能实现,但是结构体和类有着本质区别:类是引用类型,结构体是值类型。由于结构体是值类型,所以它虽然有构造函数但是没有析构函数,内存释放系统自动管理不需要开发人员过多关注;
类的类型方法使用class修饰(以便子类可以重写),而结构体、枚举的类型方法使用static修饰(补充:类方法也可以使用static修饰,但是不是类型方法而是静态方法;另外类的存储属性如果是类型属性使用static修饰,而类中的计算属性如果是类型属性使用class修饰以便可以被子类重写;换句话说class作为“类型范围作用域”来理解时只有在类中定义类型方法或者类型计算属性时使用,其他情况使用static修饰[包括结构体、枚举、协议和类型存储属性]);
类的实例通常称之为“对象”,而在Swift中结构体也可以有实例,因此对于很多二者都可以实现的功能,在文中称之为实例而没有使用对象的概念。
枚举
在其他语言中枚举本质就是一个整形,只是将这组相关的值组织起来并指定一个有意义的名称。但是在Swift中枚举不强调一个枚举成员必须对应一个整形值(当然如果有必要仍然可以指定),并且枚举类型的可以是整形、浮点型、字符、字符串。首先看一下枚举的基本使用:之所以没有将枚举、结构体放到上面的数据类型部分介绍一方面Swift中的枚举、结构体和其他语言中有较大差别,另一方面是因为这个部分的介绍要用到前面的知识。
泛型
泛型可以让你根据需求使用一种抽象类型来完成代码定义,在使用时才真正知道其具体类型。这样一来就好像在定义时使用一个占位符做一个模板,实际调用时再进行模板套用,所以在C++中也称为“模板”。泛型在Swift中被广泛应用,上面介绍的Array<>、Dictionary<>事实上都是泛型的应用。通过下面的例子简单看一下泛型参数和泛型类型的使用。相关文章推荐
- Swift:什么时候使用结构体和类
- 基于Swift语言开发微信、QQ和微博的SSO授权登录代码分析
- Swift 数组的常用操作
- Swift String 一些常用方法
- Swift 2.0 项目中利用中自定义行高 时遇到的问题?
- Swift学习——Swift解释特定的基础(七)
- Swift和OC混用
- Chapter 17 Core Data iOS 8 -Swift Programming cookBook 读书笔记
- swift 字符串和字符相关
- swift -NavigationController,代理传值
- swift -UIView的使用
- swift -类的定义及使用
- swift -结构体
- swift -函数、函数指针
- Swift入门(九)——String与Int、Double、Float等数字相互转换
- Swift爬行篇-- UIButton
- Swift- 枚举中的rawValue和hashValue
- swift-08-使用键值对儿统计字符在字符串中出现的次数
- swift-08-使用键值对儿统计字符在字符串中出现的次数
- swift-07-使用for-in 遍历数组