Swift是一门苹果公司于2014年首次推出的语言,主要应用领域就是苹果公司各种设备的软件开发。从手机到手表,从电视盒子到电脑,只要是苹果自家的产品,统统囊括。所以,这当然是融入苹果生态开发的必备编程语言。讲到这,可能有小伙伴会想,我对苹果生态的软件开发完全不感兴趣,所以这门语言就和我没关系了呗?

先别着急关掉这个页面。本文的目的就是让程序员朋友们能一窥Swift的优秀设计,了解一下这门年轻的语言值不值得学习。

在正式进入到Hello World!之前,先容我介绍几个Swift的非编程特性:

如果你对这段不感兴趣,往后翻可以直接到编码阶段

1. 开源

是的,这是一门开源的语言,采用Apache License 2.0许可。代码就在GitHub,并且此时此刻的Star数为58.3k,着实不低了。

2. 跨平台

请不要惊讶,作为一门苹果公司推出的,用来开发苹果生态产品的编程语言居然是跨平台的。除了macOS, 它还支持LinuxWindows,更夸张的是即使是iOS的老对手Android,这门语言也是支持的。毕竟开源的力量是无穷的。

不过这里要泼个冷水,支持是一回事,好用又是另外一回事。并且在非苹果自家的平台上运行,因为对应UI库的缺失。Swift更适合扮演后端编程语言的角色。

3. 活跃

毕竟是一门年轻的语言,截至2021年末,最新的Swift最新的版本为5.5.2,侧面体现了这门语言的更新之频繁。

凡事都要两面看,“活跃”带来的未必都是好事,过分的“活跃”发版,意味着多变,很多东西没有沉淀,同时也意味着程序员需要付出更多的精力才能跟上这门语言的节奏。不过好在经过几年的野蛮生长,目前Swift的特性演进已经放缓,这点从5.0的版本发布于2019年初即可看出端倪。

4. 苹果公司主导

这也值得一说么?别误会,我并不是要吹嘘苹果公司如何如何。而是想聊聊关于成就包袱的哲学。

对于一个人,过去曾给他带来荣耀的成就,最终都会变成某种包袱伴其左右,对于一个公司亦如是,这话不是鲁迅说的,是我自个儿想的。当你看到多少功成名就的人固步自封,甚至被捧杀后又跌落神坛;又有多少公司尾大不掉,深陷泥潭,最终被历史淘汰,或许能理解我的这句话。

就拿我最喜欢的语言Java来说,给世人的印象就是保守,它有广袤的生态,相对悠久的历史,储量很大的程序员队伍,这些是它的成就,恰恰也是它的包袱。生态的繁荣,导致很多早已Out的解决方案还能苟延残喘;悠久的历史导致生产环境有很多现存的系统,即使千疮百孔,但无人敢碰,只能继续延用老的架构;庞大的程序员队伍,就像物理定律一般,质量越大,惯性越大,在巨大惯性的作用下,大家你看看我,我看看你,然后心安理得地选择了固步自封。就是因为拖着这些包袱,Java语言或者说Java生态迟迟不能跟过去切割,总给人一种迟暮臃肿之感,即使这些刻板印象,只是某种未加深入了解的错觉,但也在无形中矮化了其在新晋程序员心目中的印象。

我们再回头看看Swift的缔造者——苹果公司。这是一个不论在消费者还是在生产者(程序员)队伍中都极具号召力的公司。并且它很有主见,做事不拖泥带水。笔记本接口改革,砍掉HDMI,砍掉SD卡槽,说砍就砍,说加就加。丝毫不影响销量。每年iOS大版本更新,升级率也傲视整个手机界。所以,苹果公司是一个敢于跟过去切割的公司,在多年的品牌文化熏陶下,它的用户们也早已习惯了这种“切割”。同时围绕着苹果生态的程序员,大都跟苹果公司的消费者一样,拥有异于其他技术栈的粘性,毕竟要入坑苹果生态开发,需要买个Mac,十有八九还要注册个苹果开发者账号,年租金688,这些可都是真金白银的投入,就算是图个心理安慰,他们追随苹果公司脚步的意愿也不是其他技术栈程序员可比拟的。

当然,最令其他公司难望项背的实力还是苹果公司对上下游无与伦比的掌控力。一个技术点,从硬件设计,到操作系统升级与API开放,再到号召程序员跟进完全都受其领导。比如iOS13新增的文档扫描API,显然依赖于苹果之前在其芯片中对机器学习算力单元的布局,一旦硬件铺开,苹果就可以直接在对应的iOS版本中提供API,而广大开发者几乎都会迅速跟进,早在iOSbeta阶段就可以试水磨练自己的App。等开发者和苹果的beta系统磨合得差不多了,随着正式版iOS向全球用户推送,数月之内广大的终端消费者都会陆续更新他们的iOS版本——对,你可能会说,肯定会有不少年龄大的或者不会更新系统版本的消费者。可是这些消费者恰好也跟愿意在App Store花钱购买App的消费者不重合啊——所以你看到没?这是一个运作良好的正反馈循环。

只要回头看看Android开发,你就会明白这个反馈循环是开发者梦寐以求的。在Android平台上,不管Google拿出什么杀手锏级别的API,广大开发者们都没有勇气在第一时间跟进。因为谁也不知道那些造手机的硬件厂商会在什么时间跟进Android大版本。而只要有那么一两个主流手机厂商更新慢了,那么软件开发者就不愿,或者不敢过早的介入新版API的开发,因为没有人愿意陷入兼容性调试的噩梦以及多版本代码并线开发的深渊。显而易见的,这就是一个负反馈循环,作为Android的供应商Google空有一番力却使不出来,而广大软件开发者们亦是多方掣肘牵绊太多。


好了,关于主观的铺垫就讲到这里。下面我们该进入Swift的编程世界了。本文主要专注语言语法本身的介绍,所以不会过多介绍开发环境的搭建以及IDE的使用。如果你需要动手尝试Swift的话,最好有个Mac然后安装好Xcode,或者你有个iPad,也可直接安装Swift Playgrounds,相信第一眼看到这个截图就会被它所吸引。

CleanShot-2021-12-30-at-11.33.17

如果你是Windows或者Linux等非苹果生态的用户,可以在这里找到相应平台的安装包,https://www.swift.org/download/ ,祝你好运,我们进入正题。


1. Hello World!

print("Hello, world!")

2. 变量与常量

var myVariable = 42
myVariable = 50
let myConstant = 42
  • var 代表变量
  • let 代表常量
  • 在提供数据的情况下,类型可以自动推断
  • 如果你需要指定类型,可以像这样
let explicitDouble: Double = 70

如果你想直接组合一个字符串和数字,就会报错,像这样:

let label = "The width is "
let width = 94
let widthLabel = label + width //🙀Binary operator '+' cannot be applied to operands of type 'String' and 'Int'

但是你可以这样:

let widthLabel = label + String(width)

还有一种更优雅的方式把值整合进字符串,像这样:

let apples = 3
let oranges = 5
let appleSummary = "I have \(apples) apples."
let fruitSummary = "I have \(apples + oranges) pieces of fruit."

当然多行字符串也是一门现代语言所必备的技能:

let quotation = """
I said "I have \(apples) apples."
And then I said "I have \(apples + oranges) pieces of fruit."
"""

3.数组与字典

用中括号可以快速定义数组:

var shoppingList = ["catfish", "water", "tulips"]
shoppingList[1] = "bottle of water"
shoppingList.append("blue paint")

如果你需要定义一个字典类型(在Java里它比较像HashMap)可以这样:

var occupations = [
    "Malcolm": "Captain",
    "Kaylee": "Mechanic",
 ]
occupations["Jayne"] = "Public Relations"

如果是定义空的数组或字典,可以这样:

let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
//当然被声明为let,就不可添加元素喽

遍历数组也很简单,像这样:

let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
    if score > 50 {
        teamScore += 3
    } else {
        teamScore += 1
    }
}
print(teamScore) //会输出:11

4. Optional与nil

我想每一个使用面向对象语言编程过的人,都与空指针之类的报错战斗过。作为一个Java程序员,NullPointerException绝对是我这辈子遇到过最多的报错,没有之一。

好在Swift从语法层面解决了这个问题。
如果一个变量,我还没想好放什么值,先用nil(类比为Java里的null)顶一下。

var x:String = nil //🙀'nil' cannot initialize specified type 'String'

你将得到一个报错,也就是说String里面是必须有内容的。如果你执意如此,就得这样写:

var x:String? = nil

这样你得到的就不是String了,而是一个Optional,它像一种包装器,把一个String装了进去。但是当你要使用它的时候,因为拿到的是个盒子,你也不知道里面有没有String,所以就需要多一步,把包装打开确认里面有String才行。我们来看下官方示例:

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let name = optionalName {
    greeting = "Hello, \(name)"
}

代码中的第三行,就体现了拆包的动作,通过一次let操作,就把optionalName拆成了name,而这个name就是彻头彻尾的String类型了,在花括号范围内可以任意使用, 不用担心nil的问题。如果你觉得平白无故多了个叫name的东西有点碍眼,上面的代码还可以写成这样:

var optionalName: String? = "John Appleseed"
var greeting = "Hello!"
if let optionalName = optionalName {
    greeting = "Hello, \(optionalName)"
}

还有一种场景,就是在遇到nil的时候提供一个默认值,比如这样:

let nickname: String? = nil
let fullName: String = "John Appleseed"
let informalGreeting = "Hi \(nickname ?? fullName)"

你大概也能猜到,如果nickname有值,就用它,反之,就用fullName拼装到informalGreeting中。


讲到这,你有没有觉得这门语言似乎有点意思了,希望你可以动手体验一下Swift编程。咱们下节课见喽。