Swift入门指南(iOS9 Programming Fundamentals With Swift)
语言
第一章:从概念与实践上介绍Swift程序的结构;
第二章:介绍Swift 函数;
第三章:介绍Swift变量;
第四章:介绍Swift对象类型——类、结构体与枚举,以及多态 类型转换 协议 泛型 及 扩展;
第五章:比较庞杂:流程控制结构,错误处理,自定义运算符,访问控制(私有性),内省机制(反射)与内存管理;
第一章:Swift架构纵览
本章介绍Swift语言的整体架构与本质特性;
1.1 基础
print("hello")
print("world")
Swift是一门编译型语言,这意味着代码必须先构建(通过编译器,由文本转换为计算机可以理解的某种底层形式),然后再执行并根据指令完成任务
Swift编译器十分严格:Swift编译器的错误和警告信息涵盖范围非常广;
1.2 万物皆对象
对象:指的是你可以向其发送消息的某个实体;
Swift中,消息发送语法采用的是点符号;
万物皆对象的想法表明即便是“原生”的语言实体都可以接收消息;比如 1;
1.sayHello()
extension Int {
func sayHello() -> Void {
print("hello I am \(self)")
}
}
Swift中,对象类型是可扩展的,这意味着你可以定义该类型下自己的消息;
Swift中,1是一个对象;而在OC中1是一个原生或标量内建数据类型;
Swift中是不存在标量类型的,所有类型最终都是对象类型;
1.3 对象类型的三种风格
在很多语言中(如OC),对象是一个类或类的实例;
Swift拥有类与实例,不过,1既不是类也不是实例,它是一个结构体;
Swift中还有另外一个可以接收消息的实体,叫做枚举;
因此,Swift拥有三种对象类型:类 结构体 枚举,可以理解为对象类型的三种风格;
1.4 变量
变量:指的是对象的名字;
在Swift中,不存在没有名字的变量,所有变量都必须要声明;
声明变量名,使用关键字let和var;配合赋值运算符进行初始化(‘=’等号并不是相等性断言);
使用let声明的名字是不能替换掉其对象的;
通过let声明的变量是个常量,其值只能被赋予一次并且不再变化;(Swift对常量的处理更高效)
可以通过var声明一个名字来实现最大灵活性;
变量也是有类型的,其类型是在声明时创建的,而且永远不会改变;
约定:类型名首字母大写,变量名首字母小写;
let one = 1
var two = 2
two = one
print(two)
1.5 函数
函数:由一系列代码构成,并且可以运行;
一般来说,函数有一个名字,这个名字通过函数声明得到;
go()
func go() -> Void { let one = 1 var two = 2 two = one print(two)}
1.6 Swift文件的结构
非main.swift文件;
Swift文件的顶层部分:
1.模块import 语句:模块是比文件更高层的单元,一个模块可以包含多个文件,在Swift中,模块中的文件能够自动看见彼此;但是如果没有import语句,那么一个模块是看不见其他模块的;
如,在iOS程序中使用Cocoa,文件第一行会使用import UIKit;
2.变量声明:声明在文件顶层的变量叫做全局变量,只要程序还在运行,他就会一直存在;
3.函数声明:声明在文件顶层的函数叫做全局函数,所有代码都能看见并调用它,无需向任何对象发送消息;
4.对象类型声明:指的是类、结构体或枚举的声明;
比如,下面一个合法的Swift文件,包含一个import语句、一个变量说明、一个函数声明、一个类声明、一个结构体声明,以及一个枚举声明;
import UIKit
var one = 1
func changeOne(){
}
class Manny {
}
struct Moe {
}
enum Jack {
}
实例中,每一个花括号中还可以加入变量声明、函数声明与对象类型声明;
下面是一个合法的Swift文件结构示例:testOne.swift
let testone = testOne()
print(testone)
import UIKit
var one = 1
func changeOne(){
let two = 2
func sayTwo(){
print(two)
}
class Klass{
}
struct Struct{
}
enum Enum{
}
one = two
}
class testOne {
let name = "Manny"
func sayName() -> Void {
print(name)
}
class Klass{
}
struct Struct{
}
enum Enum{
}
}
struct Moe {
let name = "Moe"
func sayName() {
print(name)
}
class Klass{
}
struct Struct{
}
enum Enum{
}
}
enum Jack {
var name:String{
return "Jack"
}
func sayName() {
print(name)
}
class Klass{
}
struct Struct{
}
enum Enum{
}
}
这种类声明中嵌套类声明的方式,其实意义不大,但它是合法的;
1.7 作用域与生命周期
Swift程序中,一切事物都有作用域;
规则就是:一个事物可以看到与自己相同层次或是更高层次的事物;
层次有:
1.模块是一个作用域;
2.文件是一个作用域;
3.对象声明是一个作用域;
4.花括号是一个作用域;
一个事物的生命周期与其外部作用域的生命周期是一致的;
1.8 对象成员
在三种对象类型(类 结构体 枚举)中,声明在顶层的事物具有特殊的名字;
对于类:
声明在对象顶层的变量,叫做该对象的属性;
声明在对象顶层的函数,叫做该对象的方法;
声明在对象声明顶层的事物(属性,方法以及声明在该层次上的任何对象)共同构成了该对象的成员;
成员具有特殊的意义,因为它们定义了你可以向该对象所发送的信息!
1.9 命名空间
命名空间:指的是程序中的具名区域;
命名空间具有这样一个属性:如果事先不穿过区域名这一屏障,那么命名空间外的事物是无法访问到命名空间内的事物的;
基于此,我们可以在不同地方使用相同的名字而不会发生冲突;
命名空间与作用域是紧密联系的两个概念;
命名空间有助于解释在一个对象顶层声明另一个对象的意义:
如:
class Hua {
class Qiang {
}
}
这种 Qiang是一个嵌套类型,被隐藏到了Hua中,Hua就是Qiang的命名空间;
Hua中代码可以看到Qiang,但是外边的却看不到;
需要显示的指定命名空间才能穿过命名空间所代表的屏障,即Hua.Qiang
Hua.Qiang()
用的依旧是消息发送的点符号语法;
通过消息发送进入本无法进入的作用域;
1.10 模块
顶层命名空间是模块;
默认情况下,应用本身就是一个模块,因此也是命名空间;大概来说,命名空间的名字就是应用的名字;
框架也是模块,因此他们也是命名空间;
在编写iOS程序时,你会import Foundation(还有可能import UIKit,它本身又会导入Foundation),这样就可以直接使用NSString而不不写成Foundation.NSString,如果在自己的模块中,声明了一个同名的,那就只能通过命名空间区分了;
可以创建自己的框架,当然他们也都是模块;
文件层级之外的是文件所导入的库或模块;
代码总会隐式导入Swift本身,显示import Swift作为文件开始;
print就是Swift.h头文件的顶层声明的一个函数;
1.11 实例
对象类型(类 结构体 枚举)都有一个共同的特性:可以实例化;
实例化的过程就是创建该类型的一个实例;
默认情况下,属性和方法是实例属性与实例方法;
你不能将其作为消息发送给对象类型本身;只能将这些消息发送给实例;
发送给对象类型本身的是另外一种函数(类函数或是静态函数);
1.12 为何使用实例
实例属性的值的定义与特定的实例有关,这正是实例真正的用武之地;
实例是特定属性值的集合;
简而言之,实例既包含代码又包含数据;代码来自于实例的类型,并且与该类型的所有其他实例共享,不过数据只属于该实例本身;只要实例存在,其数据就一直存在;在任意时刻,实例都有一个状态,自身属性值的完整集合;实例是维护状态的一个设备,它是数据的一个存储箱。
1.13 self
实例是一个对象,对象则是消息的接收者;
实例需要通过一种方式才能将消息发送给自己,即通过self实现;
当一个实例的代码使用self时,表示引用该实例;
self是可选的,原因在于如果省略消息接收者,那么你所发送的消息就会发送给self,编译器会在底层将self作为消息接收者,不过最好别这样做!
1.14 隐私
命名空间本身并非访问内部名字的不可逾越的屏障;但如果愿意,它是可以的;
Swift提供了关键字private(还有其他的);
默认的属性是公有属性,private修饰的是私有属性;
类声明定义了一个命名空间,该命名空间要求其他对象通过额外的点符号来引用命名空间内部的事物,不过其他对象依然可以引用命名空间内部的事物;命名空间本身并不会对可见性形成屏障,而private关键字则形成了这道屏障;
1.15 设计
可以用两个短语来总结对象的本质:功能封装与状态维护;
功能封装:每个对象都有自己的职责;
状态维护:每个实例都有自己所维护的一套数据;
1.15.1 对象类型与API
每个对象类型可以接收的消息总数(即API,应用编程接口)类似于你可以让这个对象类型所做的事项列表;
Swift本身自带了一些颇具价值的对象类型,如String和Int;
1.15.2 实例创建、作用域与生命周期
对象类型定义了实例的种类以及每一种实例的行为方式;
不过这些类型的具体实例都是持有状态的‘实体’,实例方法与属性就是可以发送给实例的消息;
实例的生命周期取决于引用它的变量的生命周期;
基于对象的编程艺术要点就在于此:赋予实例足够的生命周期并让他对其他实例可见;
当应用启动时,运行时会帮你实例化相应的对象类型,构建彼此关系;运行时会创建出应用委托实例,并且让其在应用的生命周期中保持存活状态;它会创建一个窗口实例,并将其赋给应用委托的一个属性;他还会创建一个视图控制器实例,请将其赋给窗口的一个属性;最后,视图控制器实例有一个视图,它会自动出现在窗口中;
1.15.3 小结
对象的本质是类型与实例;
类型:是一组方法,用来说明该类型的所有实例可以做什么(功能封装);
实例:相同类型的实例只有属性是不同的(状态维护);