学习Swift的第一步
SwSwiftUI是一个强大的框架,用于为iOS、macOS、tvOS甚至watchOS构建用户交互式应用程序。但是,如果没有编程语言,你就无法构建软件,所以SwiftUI背后隐藏着Swift本身:一种强大、灵活、现代的编程语言,您可以将其用于所有SwiftUI应用程序。
正如马克·吐温曾经说过的那样,“成功的秘诀在于开始。”好吧,你现在就开始了,所以我们将深入学习Swift中的变量、常量和简单数据类型。
今天你有七个教程要完成。如果你想更深入地了解每个主题,可以选择进一步阅读,但除非你想并且有时间,否则你不需要阅读。无论如何,有一些简短的测试可以帮助确保你理解了关键概念。
为什么选择Swift
市面上有很多编程语言,但我认为你会非常喜欢学习Swift。这在一定程度上是出于实际原因——你可以在App Store上赚钱!——但也有很多技术原因。
Swift是一种相对年轻的语言,2014年才推出。这意味着它并没有旧语言那么多的缺陷,通常意味着解决特定问题只有一种方法。与此同时,作为一种新的编程语言,Swift建立在旧语言成功(有时是错误)基础上的各种新思想。例如,它很难意外地编写不安全的代码,它很容易编写清晰易懂的代码,而且它支持世界上所有的语言,所以你永远不会看到困扰其他语言的奇怪字符错误。
Swift本身只是一种语言,并不能在屏幕上绘制任何图形。当涉及到使用Swift构建软件时,您将使用SwiftUI:苹果强大的框架,可以创建文本、按钮、图像、用户交互等等。顾名思义,SwiftUI是为Swift构建的——它的设计初衷是利用该语言提供的强大功能和安全性,这使得构建真正强大的应用程序非常快。
所以,你应该学习Swift,因为你可以用它赚钱,但也因为它在很多事情上都做得很好。没有粗鲁,没有混乱,只有触手可及的强大力量。有什么不喜欢的?
关于本课程
自2014年Swift推出以来,我一直在教人们编写Swift,而在这一点上,Hacking with Swift是世界上最大的致力于教授Swift的网站。
一路上,我学到了很多关于什么主题最重要的知识,如何将主题组织成流畅一致的流程,最重要的是如何帮助学习者记住他们学到的主题。这门课程是所有这些学习的产物。
与我之前的工作不同,这并不是要教你Swift的每一个方面,而是要花更多的时间在最重要的功能子集上——你将在你构建的每个应用程序中一次又一次地使用的功能。是的,涵盖了一些高级语言功能,但我是根据实用性精心挑选的。当你读完这本书后,你可能想继续学习一些更高级的功能,但我怀疑你更愿意忙于学习如何使用SwiftUI。
这本书的每一章都有文本和视频两种形式,但它们涵盖的材料完全相同,所以欢迎你以最适合你的方式学习。如果你正在使用这些视频,你会注意到我有时会使用幻灯片介绍主题,有时会在Xcode中演示它们。这可能会让人觉得重复,但这是有意的——有很多东西需要学习,如果你只看到每一件事一次,它就不会留在你的记忆中!
还有最后一件事:你可能会注意到有多少章节以“如何……”开头,这是有意的——这本书是为了向你展示如何以动手的方式做事,而不是钻研理论。理论很重要,在继续学习的过程中,你会遇到很多理论,但这里的重点是坚持不懈地实践,因为我相信学习新东西的最好方法就是自己尝试。
编程是一门艺术:当你应该画画的时候,不要把所有的时间都花在削铅笔上。
如何学习本课程
这本书中展示了很多代码,我真的想鼓励你自己尝试一下——把代码输入你的电脑,运行它并查看输出,然后做一些实验以确保你理解它。
要运行本书中的代码,您应该从Mac App Store安装Xcode 15.0或更高版本。它是免费的,包括你需要遵循的一切。
本书中的所有代码都将使用Swift Playground。您可以通过启动Xcode,然后转到“File”菜单并选择“New”>“Playground”来创建一个。当被问及要创建什么样的游乐场时,请从macOS选项卡中选择“空白”,然后将其保存在您可以轻松访问的地方。
Playground就像一个小沙箱,你可以在那里轻松地尝试Swift代码,并与代码并排查看你的工作结果。你可以用一个操场来做你要做的所有工作,或者为每一章创建一个新的操场——做最适合你的事情。
如何创建变量和常量
每当你构建程序时,你都会想要存储一些数据。也许是他们刚刚输入的用户名,也许是你从互联网上下载的一些新闻报道,或者可能是你刚刚进行的复杂计算的结果。
Swift为我们提供了两种存储数据的方法,具体取决于您是否希望数据随时间而变化。创建新playground时会自动使用第一个选项,因为它将包含以下行:
var greeting = "Hello, playground"
以上代码创建了一个名称为greeting的变量,使用var定义的变量在程序运行的过程中可以修改其值。
var关键字的意思是“创建一个新变量”;
我们称之为变量greeting。你可以随心所欲地调用你的变量,但大多数时候你想让它具有描述性。
等号为我们的变量赋值。如果你不想,你不需要在等号的两侧都有这些空格,但这是最常见的样式。
我们分配的值是文本“Hello,playground”。请注意,文本写在双引号内,这样Swift就可以看到文本的开始和结束位置。
如果您使用过其他语言,您可能已经注意到我们的代码不需要在行尾使用分号。Swift确实允许使用分号,但它们非常罕见——只有当你出于某种原因想在同一行上编写两段代码时,你才会需要它们。
当你创建一个变量时,你可以随着时间的推移对其进行更改:
var name = "Ted"
name = "Rebecca"
name = "Keeley"
这将创建一个名为name的新变量,并为其赋予值“Ted”。然后它会被更改两次,首先是“Rebecca”,然后是“Keeley”——我们不再使用var,因为我们正在修改一个现有的变量,而不是创建一个新的变量。您可以根据需要更改变量,每次都会丢弃旧值。
如果你不想改变一个值,你需要使用一个常量。创建常量的工作原理几乎与创建变量相同,除了我们使用let而不是var,如下所示:
let character = "Daphne"
现在,当我们使用let时,我们创建一个常量,这是一个不能更改的值。Swift真的不会让我们这么做,如果我们尝试的话,它会显示出一个很大的错误。
不相信我?试着把它放到Xcode中:
let character = "Daphne"
character = "Eloise"
character = "Francesca"
同样,第二行和第三行中没有let关键字,因为我们没有创建新的常量,我们只是试图更改已有的常量。然而,就像我说的那样,这行不通——你不能改变一个常数,否则它就不会是常数!
重要提示:请删除显示错误的两行代码——你真的不能更改常量!
当你学习Swift时,你可以让Xcode打印出任何变量的值。你在真实的应用程序中不会使用这么多,因为用户看不到打印的内容,但它作为一种查看数据内部内容的简单方法非常有用。
例如,我们可以在每次设置变量时打印出变量的值——尝试将其输入到您的playground中:
var playerName = "Roy"
print(playerName)
playerName = "Dani"
print(playerName)
playerName = "Sam"
print(playerName)
提示:您可以通过单击Xcode playgound左侧的蓝色播放图标在其中运行代码。如果您沿着蓝色条向上或向下移动,您会看到播放图标也会移动——如果您愿意,这可以让您将代码运行到某个点,但大多数时候您会希望运行到最后一行。
您可能已经注意到,我将变量命名为playerName,而不是playername、player_name或其他替代名称。这是一个选择:Swift并不在乎你给常量和变量取什么名字,只要你在任何地方都以同样的方式引用它们。所以,我不能先使用playerName,然后再使用playername——Swift认为这两个名字是不同的。
尽管Swift不在乎我们如何命名数据,但我使用的命名风格是Swift开发人员的标准——我们称之为约定。如果你很好奇,这种风格被称为“驼峰式”,因为名字中的第二个和后续单词以大写字母的小凸起开头:
let managerName = "Michael Scott"
let dogBreed = "Samoyed"
let meaningOfLife = "How many roads must a man walk down?"
如果可以的话,更喜欢使用常量而不是变量——这不仅让Swift有机会更好地优化你的代码,而且还让Swift确保你永远不会意外更改常量的值。
如何使用字符串
当你将文本赋给一个常量或变量时,我们称之为字符串——想象一下,一堆拼字游戏方块被串在字符串上,形成一个单词。
Swift的字符串以双引号开始和结束,但你在引号内放什么取决于你。您可以使用简短的字母文本,如下所示:
let actor = "Denzel Washington"
您可以使用标点符号、表情符号和其他字符,如下所示:
let filename = "paris.jpg"
let result = "⭐️ You win! ⭐️"
你甚至可以在字符串中使用其他双引号,只要你小心地在它们前面加一个\,这样Swift就能理解它们在字符串中,而不是在字符串末尾:
let quote = "Then he tapped a sign saying \"Believe\" and walked away."
别担心——如果你错过了反斜杠,Swift肯定会告知你的代码有错误。
字符串的长度没有现实的限制,这意味着你可以用字符串来存储很长的东西,比如莎士比亚的全集。然而,你会发现Swift不喜欢字符串中的换行符。所以,这种代码是不允许的:
let movie = "A day in
the life of an
Apple engineer"
这并不意味着你不能跨多行创建字符串,只是Swift需要你对它们进行特殊处理:不是在字符串的任一侧使用一组引号,而是使用三个引号,如下所示:
let movie = """
A day in
the life of an
Apple engineer
"""
这些多行字符串并不经常使用,但至少你可以看到它是如何做到的:开头和结尾使用三个引号,你的字符串在它们之间。
一旦你创建了字符串,你会发现Swift为我们提供了一些有用的功能来处理它的内容。随着时间的推移,您将了解更多关于此功能的信息,但我想在这里向您介绍三件事。
首先,您可以通过在变量或常量的名称后写.count来读取字符串的长度:
print(actor.count)
因为这个字符串actor是“Denzel Washington”,所以会打印17个——名字中的每个字母一个,加上在中间的空格。
如果你不想的话,你不需要直接打印字符串的长度——你可以把它赋值给另一个常数,就像这样:
let nameLength = actor.count
print(nameLength)
第二个有用的功能是upercased(),它返回相同的字符串,除了它的每个字母都是大写的:
print(result.uppercased())
是的,这里需要开括号和闭括号,但count不需要。随着你的学习,原因会变得越来越清楚,但在你学习Swift的早期阶段,最好这样解释这种区别:如果你让Swift读取一些数据,你不需要括号,但如果你要求Swift做一些你做的工作。这并不完全正确,因为你稍后会学习,但这足以让你现在继续前进。
最后一个有用的字符串功能叫做hasPrefix(),它让我们知道字符串是否以我们选择的一些字母开头:
print(movie.hasPrefix("A day"))
还有一个hasSuffix()对应项,它检查字符串是否以文本结尾:
print(filename.hasSuffix(".jpg"))
重要提示:Swift中的字符串区分大小写,这意味着使用filename.hasSuffix(“.JPG”)将返回false,因为字符串中的字母是小写的。
如何存储整数
当你处理3、5、50或500万等整数时,你正在处理Swift所称的整数,简称Int——如果你好奇的话,“整数”最初是一个拉丁词,意思是“整体”。创建一个新的整数就像创建一个字符串一样:根据你想要一个常量还是变量,使用let或var,提供一个名称,然后给它一个值。例如,我们可以创建一个这样的分数常数:
let score = 10
整数可以非常大——超过数十亿、超过数万亿、超过千万亿,甚至达到五分位数,但它们也可以非常小——它们可以容纳高达五分位数的负数。当你手写数字时,很难看清发生了什么。例如,这是什么数字?
let reallyBig = 100000000
如果我们用手写出来,我们可能会写“100000000”,很明显这个数字是1亿。Swift也有类似的东西:你可以使用下划线、_来按你想要的方式分解数字。因此,我们可以将之前的代码更改为:
let reallyBig = 100_000_000
Swift实际上并不关心下划线,所以如果你愿意,你可以写这个:
let reallyBig = 1_00__00___00____00
最终结果是一样的:reallyBig被设置为值为100000000的整数。
当然,你也可以使用你在学校学到的算术运算符从其他整数中创建整数:+表示加法,-表示减法,*表示乘法,/表示除法。例如:
let lowerScore = score - 2
let higherScore = score + 10
let doubledScore = score * 2
let squaredScore = score * score
let halvedScore = score / 2
print(score)
Swift不是每次都创建新的常量,而是有一些特殊的操作,以某种方式调整整数并将结果重新分配给原始数字。
例如,这将创建一个等于10的计数器变量,然后再添加5:
var counter = 10
counter = counter + 5
您可以使用简写运算符+=,而不是写counter=counter+5
,它直接将一个数字加到所讨论的整数上:
counter += 5
print(counter)
这完全是一样的,只是打字更少。我们称这些为复合赋值运算符,它们有其他形式:
counter *= 2
print(counter)
counter -= 10
print(counter)
counter /= 2
print(counter)
在我们结束整数之前,我想提最后一件事:和字符串一样,整数也有一些有用的功能。例如,您可以对一个整数调用isMultiple(of:),以确定它是否是另一个整数的倍数。
所以,我们可以问120是否是这样的三的倍数:
let number = 120
print(number.isMultiple(of: 3))
我在那里对一个常数调用isMultiple(of:),但如果你愿意,你可以直接使用这个数字:
print(120.isMultiple(of: 3))
如何存储小数
当你使用3.1、5.56或3.141592654等十进制数字时,你使用的是Swift所称的浮点数。这个名字来源于计算机存储数字的复杂方式:它试图将123456789等非常大的数字存储在与0.0000000001等非常小的数字相同的空间中,唯一的方法是根据数字的大小移动小数点。
这种存储方法导致十进制数对程序员来说是出了名的问题,你只需要两行Swift代码就可以尝到这一点:
let number = 0.1 + 0.2
print(number)
当它运行时,它不会打印0.3。相反,它将打印0.30000000000000004——0.3,然后是15个零,然后是4,因为……好吧,就像我说的,它很复杂。
稍后我会解释为什么它很复杂,但首先让我们专注于重要的事情。
首先,当你创建一个浮点数时,Swift会将其视为Double。这是“双精度浮点数”的缩写,我意识到这是一个相当奇怪的名字——多年来,我们处理浮点数的方式发生了很大变化,尽管Swift在简化方面做得很好,但有时你可能会遇到一些更复杂的旧代码。在这种情况下,这意味着Swift分配的存储量是一些旧语言的两倍,这意味著Double可以存储绝对巨大的数字。
其次,Swift认为小数是一种与整数完全不同的数据类型,这意味着你不能将它们混合在一起。毕竟,整数总是100%准确的,而小数则不是,所以Swift不会让你把两者放在一起,除非你特别要求这样做。
在实践中,这意味着你不能做像将整数加到小数点这样的事情,所以这种代码会产生错误:
let a = 1
let b = 2.0
let c = a + b
是的,我们可以看到b实际上只是伪装成十进制的整数2,但Swift仍然不允许运行该代码。这被称为类型安全:Swift不会让我们意外地混合不同类型的数据。
如果你想实现这一点,你需要明确地告诉Swift,它应该将b中的Double转换为Int:
let c = a + Int(b)
或者将a中的Int转换为Double:
let c = Double(a) + b
第三,Swift根据你提供的数字来决定你是想创建Double还是Int——如果其中有一个点,你就有一个Double,否则它就是Int。是的,即使点后面的数字是0。
所以:
let double1 = 3.1
let double2 = 3131.3131
let double3 = 3.0
let int1 = 3
结合类型安全性,这意味着一旦Swift决定了常量或变量的数据类型,它必须始终保持相同的数据类型。这意味着这段代码很好:
var name = "Nicolas Cage"
name = "John Travolta"
但这种代码不是:
var name = "Nicolas Cage"
name = 57
这告诉Swift名称将存储一个字符串,但随后它尝试在其中放入一个整数。
最后,十进制数具有与整数相同的运算符和复合赋值运算符范围:
var rating = 5.0
rating *= 2
许多较旧的API使用一种稍有不同的存储十进制数的方式,称为CGFloat。幸运的是,Swift允许我们在所有需要CGFloat的地方使用常规的Double数,所以尽管你会不时看到CGFloat出现,但你可以忽略它。
如果你很好奇,浮点数之所以复杂,是因为计算机试图使用二进制来存储复杂的数字。例如,如果你将1除以3,我们知道你得到了1/3,但这不能以二进制形式存储,因此该系统旨在创建非常接近的近似值。它非常高效,错误很小,通常无关紧要,但至少你知道为什么Swift不让我们意外地混合使用Int和Double!
本文翻译自hackingwithswift
评论区