迅速

我现在要来写一系列关于iOS程式开发的文章。不是为了教学,而是为了把我懂的知识整理起来,系统化。里面的概念可能跟别人讲的不一样,不保证我写的是对的。

我会用英文来表示技术性词汇。

首先,我是用Swift来写app的。Swift是一种编程语言(程式语言)。编程语言是一种写给编译器(编译器)看的语言,而不是电脑硬体直接看得懂的。硬体看得懂的语言叫做二进制代码(二进位码),而编译器的作用就是把编程语言编译成二进制。

Binary就是长这个样子— —只有1跟0。很容易的,要人类用这种方法去写程序,有点太麻烦了,所以才会有人类更容易理解的编程语言出现。这些编程语言大多都是都市套用而Swift在编程语言当中又是属于高阶的,也就是一种高级编程语言。简单地说就是越像英文就可以阶入,而Swift确实是非常接近口语英语了。

Swift社区特意写了一个API设计指南,去推广“清晰度之上”这个美学观念。什么意思呢?就是说在用Swift写代码的时候,最好写得清楚一点,让其他读代码的人可以更容易理解你在写什么。

Swift的基本语法有以下几个。

分配(分配)

将单等号(=)后面的东西分配(分配)给单等号前面的变数/常数。用白话来说的话,就是把一个东西放到容器里的过程。某种说,

a = 1 

就是把「1」这个值放到「a」这个容器里面的意思。

呼叫(呼叫)

要求执行某个功能(函式)的意思。函式简单来说就是一个动作,某种说:

 print(a) // 把 a 的內容印出來。 

当中, print是函式的名字,而加上括号就代表你要机器在这里去执行这个函式。这,光是写print ,该函式是不会被呼叫的,还要加括号才行。最后,括号里面的东西就是你要给函式的东西。

有没有加括号,差异真的很大。某些说以下这两句所代表的意思完全不同:

 // 呼叫 randomInt 函式並將其輸出值指派給 a。 
a = randomInt()
// 將 randomInt 函式本身指派給 a。
a = randomInt

然而,对有参数(参数)的功能来说,加括号不代表一定就是调用,还要丢参数进去才算。有时说以下语句都是将combine这个功能分配给a的意思:

 // 省略參數列表。 
a = combine
// 把參數名都寫出來。
a = combine(a:b:)

参数又是什么呢?首先,功能就像是一台小机器,被呼叫的时候它就会去执行它里面的程序代码,一行一行。最后,它会输出一个值,或者说return(传回)一个值。而参数,就是一个功能在执行时需要输入的一组值。例如说,如果我们把combine这个功能的功能设计成把两个输入值加起来再输出,那这两个输入值就是它的参数。以下就是呼叫combine的句型:

 // 輸入 1 與 2 為 combine 的參數,並將 combine 的傳回值指派給 a。 
a = combine(a: 1, b: 2)

会员访问(成员访问)

在Swift里面,有些东西是可以有成员的。什么是成员呢?就是指“属于另一个东西”的东西。

比方说,假设每个人都有名字,那我们要访问某个人的名字的话就是这么做:

 // 將 somePerson 的 name 印出來。 
print(somePerson.name)

简单来说,这里的英文句点(。)实际上就是中文的“的”或英文的“’s”所有格。然后,它也可以串连起来写:

 // 將 andrew 的 father 的 name 印出來。 
print(andrew.father.name)

功能也可以作为成员来被存取:

 // 叫 andrew 去 jump。 
andrew.jump()
// 將 andrew 的 jump 動作指派給一個叫做 action 的容器。
action = andrew.jump
// 接下來再呼叫 action 的話,執行的就會是 andrew.jump。
action()

函数本身是没有成员的,所以不能这样写:

 combine.a 

但是,如果呼叫了一个功能的话,那它会被视为它的传回值。某些说:

 // 會被視為 3。 
combine(a: 1, b: 2)

而传回值是可能会有成员的。所以,这种写法是可能的:

 // 用 keira 去執行 andrew 的 makeChild 函式,產出一個東西之後,印出他的 name。 
print(andrew.makeChild(with: keira).name)

上面这个例子当中, andrew.makeChild(with: keira)整串会andrew.makeChild(with: keira)一个东西,而这个东西有成员的话,就可以直接接在后面去存取。所以我们这里访问的不是andrew.makeChild这个功能的成员,或者它成为的东西的成员。

声明(宣告)

在Swift里,在使用任何的东西之前,必须先创造它。这个过程,就叫做宣言(宣告)。而不同种类的东西,宣告的方法也会不同。

名称(名/容器)

宣告容器的方法有两种:

 let a 
// 或
var a

这两种方法创造出来的容器性质是不一样的。用let创造出来的是constant(常数),放东西进去之后就不能再换了。用var做出来的是variable(变数),东西放进去之后还可以用别的东西去替换。

然而,以上的宣告是不合格的,因为Swift很容易重视“型别”。简单就是,我们要让编译器知道每个一个容器可以装的是哪一种东西。所以,如果我们想让a装的是整体的话,就要这样宣告:

 let a: Int 
// 或
var a: Int
// 「Int」是「整數」這個型別的名字,來自英文「Integer」。

然后,我们才可以把东西放到这个容器里面:

 a = 1 

要注意的是,以下这一段是只有变数容器才办得到的事情:

 a = 1 
a = 2

因为用let宣告出来的常数容器只能分配一次,而用var宣告出来的变数容器没有这种限制。

那这样的话,用let不是很不方便吗?实际上常数最大的特点就是确保容器跟内装物的关系是不可改变的。如果都用let来创造容器的话,整个代码的逻辑是会变得比较清晰的。还有其他的好处,可以去查“ Immutability(不变性)”这个概念,但这里先跳过。

最后,宣告跟分配是可以写在同一个句子里面的:

 let a: Int = 1 
// 或
var a: Int = 1

当这样写的时候,有时候我们可以省略掉型别的部分:

 let a = 1 
// 或
var a = 1

这是因为Swift编译器可以从等号后面的东西去判断该容器的类型别应该是什么。

要注意的是,Swift官方手册里将在这里提到的“容器”称为“ name(名)”,但我为了方便还是继续用“容器”来称呼变数与常数。

功能(函式)

在用任何的功能之前,我们要先定义它。某些说, combine的定义可以写成这样:

 // 定義 function 的名字,參數列表(包括參數名與參數型別),以及回傳值的型別。 
func combine(a: Int, b: Int) -> Int {
// 創造一個叫做 c 的容器,並將 a + b 的結果放進去。
let c = a + b
// 回傳 c。
return a + b
}

要特别讲的是,被大括号「{}」包起来的叫作code block(程式码块)。Swift以此来组织程式码。像这里,在功能的尾巴就有一个code block,而这个程式码block就是当combine被呼叫的时候,实际上会执行的程式码。

在Swift里,特别的是功能本身也有它的型别。拿combine来说,它的型别是这样的:

 // 拿兩個 Int 型別的參數,並回傳一個 Int 值的 function type。 
(Int, Int) -> Int

而前面提到,功能也可以被放入容器里面。所以如果我们要把combine这个功能放到a这个容器里的话,我们就要把a宣告成这个样子:

 var a: (Int, Int) -> Int 
a = combine
// 或
a = combine(a:b:)
// 也可寫成一句話。
var a: (Int, Int) -> Int = combine
// Swift compiler 有時可以猜出 function 的型別。
var a = combine

构造(构造)

简单来说,除了IntStringString )这种Swift内建的型别之外,我们也可以来写自己的型别。这样说:

 // 宣告一個叫做 Person 的 struct。 
struct Person {
// 宣告 Person 擁有一個叫做 name 並屬於 String 型別的容器。
let name: String
// 宣告 Person 擁有一個叫做 jump 的 function。
func jump() {
// 一些執行碼。
}
}

如此定义之后,我们就可以创造该型别的容器:

 let andrew: Person 

并使用该容器:

 // 創造一個 Person 的 instance(實體)並指派給 andrew。 
andrew = Person(name: "Andrew Bradford")
// 印出 andrew 的 name。
print(andrew.name) // Andrew Bradford
// 叫 andrew jump。
andrew.jump()

摘要

所有的宣告本身,在宣告的当下是不会被执行的。会被执行的是调用,分配,与存取容器本身或容器的成员的时候。写Swift基本上就是在设计函数与type,并且在正确的,时机去使用它们。当然,也是可以一行一行的告诉Swift编译器里面的,再由系统去决定什么时候要呼叫哪段程式码。换句话说,大部分的code都会在大括号里面,甚至是大括号的大括号里面。