很多刚开始走iOS学习路线的人一上来就直接拖Interface Builder的控件、画跳转页面结果没三天就卡在“这句Swift代码到底在干什么”上面。我见过太多类似的案例项目能跑起来但换个需求就改不动因为连语言本身都没建立起直觉。这篇内容是iOS学习路线里Swift基础的第一部分先不碰界面只把语言地基打好——变量、数据类型、Optional、控制流、集合这些是后面啃UIKit、SwiftUI时每天都会用到的东西。适合两类人完全零基础、打算入行iOS开发的有Python/Java等其他语言基础、想快速迁移到Swift的。第二类人尤其要注意Swift有很多设计思路跟动态语言是拧着的越早掰过来越好。1. 学Swift先别急着建App工程Playground才是第一站的正确姿势1.1 为什么练习环境选Playground而不是新建项目很多新手的第一反应是打开Xcode新建一个App工程然后写两句print看看效果。结果光等模拟器启动就耗掉五分钟中间还夹杂着签名报错、证书问题、各种工程配置——这些和Swift语法本身一点关系都没有却能把学习热情磨灭一半。Playground解决的问题就是“快速验证”。它相当于一个实时跑代码的草稿本你敲一行右侧立刻显示结果。对Swift基础的语法学习来说这种即时反馈比任何花哨的项目模板都重要。具体操作上在Xcode里选择File - New - Playground模板选Blank即可。平台那里有个细节如果你只想学纯语法选macOS就够了开头真的没必要选iOS。因为Playground会按平台自动导入对应的基础框架而Common的部分两边完全一样先省掉iOS专属库的干扰能让你把注意力集中在语言本身。1.2 Playground里的三个实际操作细节习惯用工程写代码的人在Playground里通常会犯这几个小错在工程里你得写代码入口、注意文件结构但Playground文件本身就是顶层代码直接写变量、调函数就好写在函数外面的print会按照代码顺序执行。输出面板被日志刷满时用CommandK清空结果而不是把代码删掉。如果代码一直飘红但语法看着没问题有可能是Playground版本和当前Xcode默认编译器不匹配。Xcode升级之后旧Playground会提示Migrate点一下确认即可不用重写代码。还有一点容易被忽略Playground里常见的import UIKit或import Foundation不要删。虽然print这种基础操作不依赖它们但后面练习字符串API、日期处理时没了Foundation会少很多可用方法。留着它顺手也让它提醒你“我现在在Swift的世界里”。1.3 一个容易被忽视的常识语言学习和框架学习是两条线作为iOS学习路线的一部分很多人有个误区以为打开Xcode建了界面就等于学会了Swift。其实语言和框架完全是两条学习线Swift解决的是“怎么写代码”UIKit/SwiftUI解决的是“界面和交互怎么组织”。先学哪一种更合理我的建议是先把Swift基础过一遍不用等全部精通但至少要能看懂、能改、能独立写简单逻辑。后面接触界面开发时你才有余力去区分“这个报错是语言层面的还是框架层面的”。实际经验表明这一步看似慢其实是最快的路。没有语言地基去硬啃框架遇到报错完全无法定位那才是真的陷进去。我在日常交流里看过不少初学者的代码绝大多数卡壳都发生在语法和类型问题上而不是框架API不会用。2. 变量与常量let用得多才说明你真的读懂了Swift的脾气2.1 var和let不是“都能声明变量”这么简单在其他语言里你声明一个变量然后再改它的值是再自然不过的事。Swift多了一个选择let。初学阶段很多人觉得let就是“加了限制的var”少用为妙这恰恰把顺序搞反了。Swift社区里有一条默认准则优先用let只有在值确实需要变化时才用var。这不是玄学风格而是有实际原因的。第一代码可读性。一个let声明的名字读者可以确定它从上到下不会变阅读时大脑能省掉一层状态跟踪。第二防止自己制造bug。线上最常见的崩溃来源之一就是某个值被不该改的地方改了。第三编译器优化。不可变值在很多场景下有更好的优化空间虽然现代编译器不一定每次都显著但这个心智模型是正确且有用的。为此你可以把let理解为“值绑定”var才是真正的“可变变量”。如果一个变量从声明之后从来没被重新赋值编译器甚至会给出warning提示你改成let。这种来自编译器的培养机制正是Swift和其他语言非常不同的地方它在日常摩擦里一点点训练你的设计直觉而不是只停留在文档里。2.2 类型推断与显式类型声明Swift支持类型推断你可以直接写let name iOS Learner var score 88编译器会自动推断出name是String类型score是Int类型。这是Swift对写代码效率的让步但它绝不等于动态语言那种“变量类型随便变”。一旦推断完成类型就固定了你再写score 一百立刻编译报错不可能通过。这种设计背后有清晰的理由Swift是静态类型语言所有类型信息在编译期就已经确定。类型推断只是减少了打字量没有牺牲类型安全。理解这一点之后你会明白下面这两种写法在语义上没有任何区别let word hello let word: String hello那显式类型在什么情况下必须补很有几种场景空数组和空字典无法推断元素类型时、函数参数和返回值需要明确对外API时、想强制指定一种字面量类型时。另外从表达意图的角度出发我建议在公共接口函数参数、返回值、公开属性上尽量写出类型在局部逻辑内部则可以放心享受推断带来的简洁。2.3 命名规范和团队协作的隐性约定Swift的命名约定是驼峰式变量名、函数名都用小写字母开头后续每个词首字母大写类型名之后会遇到的class、struct、enum用大写字母开头。比如let totalPrice 100 // 推荐 let userInfo abc // 推荐 let TotalPrice 100 // 风格怪通常不被接受这里有个小小的习惯问题命名时别用拼音也别中英混杂。在iOS学习路线初期养成好习惯后面写接口、维护代码时能省很多事。另外类型名跟变量名撞名也是常见编译报错来源比如你声明一个叫Int的变量编译器会给出非常绕的错误信息初学者极易被带偏方向。多聊一句let和var背后的思维变化每次声明一个名字你都在做一个小小的设计决策——判断它后面会发生什么。这个判断力练出来之后再写复杂类时就不容易把状态搞得一团糟。在我看来这是Swift基础中最值得潜移默化的能力比记住某个具体语法点重要得多。3. 基本数据类型Int、Double、String背后的值类型思维3.1 数值类型与平台相关的细节Swift里最基础的数值类型有Int、Double、Float、Bool加上字符串String。看起来跟其他语言差不多但细节里有几个值得注意的设计。Int是“平台原生整型”在64位设备上是64位在32位设备上是32位。对iOS开发来说现在的设备基本全是64位所以你直接使用Int完全不用担心位数问题。Swift同时也提供了Int8、Int16、Int32、Int64以及无符号版本UInt但这些在日常业务里很少直接用最多在数据协议转换、位运算时才碰得到。Float和Double的区别是精度Float用32位存储Double用64位。Swift的默认推断里有个细节小数默认推断为Double你写let pi 3.14编译器认为pi是Double而不是Float。这在跟系统API交互时非常关键因为很多函数参数把这两个类型分得很清楚你一不小心算出一个Float传参之前还得先做转换。涉及金额计算的场景Double也不是万能解高精度需求要往Decimal类型上走但那是进阶话题。第一部分只需要记住结论能用Double解决的别用Float能用Int解决的别用UInt。无符号整型在边界处理上坑很多新手尽量别碰。3.2 类型转换里藏着一个Optional的门Swift是强类型语言这意味着它没有隐式类型转换。同样是数值Int和Double之间必须显式转换不能像某些动态语言那样直接混用。这个规则很反新手直觉但它是好设计——它强迫你意识到自己在做什么样的精度选择。你可能会写这样的代码let count: Int 3 let price: Double 9.9 let total Double(count) * price // 显式把Int转成Double如果你直接写count * price编译器会报“binary operator * cannot be applied to operands of type Int and Double”。这不是Swift不够聪明而是它拒绝替你决定精度损失的方向。更有意思的是字符串转数字Int(42)返回的不是Int而是Int?也就是Optional类型。为什么因为字符串里可能不是合法数字42abc、empty都会转换失败。在Swift看来一个可能失败的转换返回值必须有能力表达“没有结果”。这就是Optional的雏形下一章会正式展开。这里给一个实用建议转换之后先检查再使用永远不要假设一定成功。很多第一次接触的人直接写强制解包Int(str)!一旦str恰好不是数字程序立刻崩溃。在Swift基础阶段我建议你刻意为这种场景练习使用if let。3.3 String的插值和它为什么是值类型String在Swift里是值类型这一点被很多人低估。值类型意味着每次赋值、传参都是一份独立的数据底层有写时复制优化但你可以先不用管实现细节。从学习角度核心结论是把一个字符串传给函数函数内部改它不会影响原来的变量。这在很多其他语言里是反直觉的在Swift里却是默认行为。字符串拼接可以直接用加号但实际开发里更常用的是字符串插值let userName 小明 let age 18 let intro 大家好我叫\(userName)今年\(age)岁插值里可以放变量、放表达式甚至放一个返回字符串的函数调用。注意一点插值里如果遇到比较复杂的表达式最好用括号包一层比如打完折价格是\(price * 0.8)。别在里面写太长的逻辑可读性会迅速下降。字符串是否相等直接用判断前缀和后缀判断用hasPrefix和hasSuffix。这些基础API在Playground里随手试一下比查文档印象要深得多。基础字符串处理这一关过了后面所有的文本展示需求都会轻松不少。4. Optional被劝退最多的地方也是Swift安全性最值钱的机制4.1 nil到底能不能用Optional的诞生背景如果你有过其他语言的开发经验大概率对null/nil既熟悉又头疼。多数语言允许任何引用类型变量为nil编译器不强制检查运行时一旦碰到就是崩溃或异常。业界对这个设计有个夸张但精准的评价价值十亿美元的错误。Swift的做法是普通变量不允许存nil。你想让一个变量“可能没有值”必须显式声明为Optional也就是在类型后面加问号var middleName: String? nil这个问号看起来只是语法糖意义却非常大。在Swift的类型系统里String?和String是两个完全不同的类型。String表示必然有值所有操作都安全String?表示可能没有值编译器要求你先解包再使用。换句话说Swift把“空值风险”从运行时提前到了编译期这是它安全性的核心。你可以把Optional理解成一个盒子它只有两种状态要么是装着值的.some要么是空着的.none。我们平常写的String?本质上就是一种枚举类型。知道这个底层模型之后后面学Optional的map、flatMap这些高阶方法时就不会犯晕。4.2 四种解包方式的对比Optional在使用前必须解包。新手阶段最常接触的有四种方式放在一起对比更清楚// 方式一强制解包 let result: String? hello print(result!) // 如果result为nil这里直接崩溃 // 方式二if let绑定 if let value result { print(value) // 只有非nil时才进入分支 } else { print(没有值) } // 方式三guard let提前返回 guard let value result else { return } print(value) // 方式四nil合并运算符 let display result ?? 默认值方式一能不能用能但我不推荐除非你能100%确定它非nil。初学阶段最忌养成的习惯就是到处加感叹号。方式二是最直观的安全解包适合在分支逻辑内部使用。方式三是iOS开发中最常见的优雅写法在函数开头把需要的值一次性检查完nil就直接return下面的主流程全是干净的非Optional逻辑。方式四是给一个后备值非常适合UI展示场景比如给可选的用户昵称设置默认文案。这四种方式不是互斥的实际代码里经常搭配使用。选择标准很简单想给默认值用??想走另一个分支用if let想在后面继续用这个值用guard let绝对不可能为nil才考虑感叹号。解包方式适用场景风险点强制解包 !确定存在值nil时崩溃if let局部分支处理作用域受限guard let提前退出后面继续用必须退出当前作用域nil合并 ??提供默认值无法区分“空”和“默认”4.3 实战中最推荐的书写习惯guard let展开聊聊guard let。它出现在函数体里时作用是在条件不满足时提前退出当前作用域。为什么我推荐新手尽快习惯它因为它能把“守护逻辑”集中在函数开头让后面的主流程可读性显著提升。举个例子func process(orderID: String?) { guard let orderID orderID else { return } // 到这里orderID已经是非Optional的String print(处理订单\(orderID)) }这里有一个细节guard的else分支必须退出当前作用域编译器强制要求里面必须写return或continue这类语句否则编译不过。这个限制初看有点烦细想就知道它是在保护你guard本来就是为了阻止程序继续执行而存在的你不退出编译器会觉得莫名其妙。还要注意Optional不只是变量有属性、函数返回值、字典取值处处都有它的身影。后面学到Dictionary时你会再次遇见它。把Optional这一节啃透相当于提前排掉了后面一大半的崩溃隐患。5. 控制流与基础函数从“认识语法”到“能写逻辑”5.1 if和switchSwift的switch没有隐式贯穿控制流在任何语言里都是基本功。Swift的if用法跟主流语言大同小异但switch有四个特性值得单独记忆。第一switch的分支默认不会贯穿。在C系语言里忘写break会导致代码继续执行下一个caseSwift写一个case的代码块后自动结束整个switch想继续往下走得显式写fallthrough。第二每个case至少要有执行语句空分支是不允许的。第三case可以匹配区间、元组、甚至带条件的表达式。最常用的是区间匹配let score 85 switch score { case 90...100: print(优秀) case 60..90: print(合格) default: print(不合格) }注意区间运算符的细节90...100包含两端60..90包含左端不包含右端。这个点特别容易混淆建议在Playground里写几个边界值比如60、90、99、100亲自验证一遍输出结果。第四switch要求穷尽所有可能的情况否则编译不通过。要么把所有case写全要么写default兜底。这一条同样来自编译器的严苛目标还是安全性和可维护性。5.2 循环的三件套与range的常见坑Swift的循环主要有for-in、while、repeat-while三种。for-in最常用一般配合范围运算符for i in 0..5 { print(i) // 输出0到4 } for i in 0...5 { print(i) // 输出0到5 }给一个实用提示如果循环体里用不到i本身可以用下划线忽略写成for _ in 0..5。这样既避免“未使用变量”的警告也让阅读者知道你不关心序号。想倒序遍历可以用reversed()for i in (0..5).reversed() { print(i) // 输出4,3,2,1,0 }while和repeat-while的区别一句话就能说清repeat-while至少会执行一次循环体因为条件检查发生在循环体之后。这个差异在别的语言里也有但很多人第一次是在Swift里才真正记住的。range还有一个常见坑空范围。比如for i in 0..0不会执行循环体。这个在拼接逻辑时容易埋雷处理边界条件之前先在纸上推演一遍范围比Debug半天下个结论快得多。5.3 函数参数的标签机制摇身一变的可读性设计Swift函数设计里有一个区别于多数语言的特点参数可以有外部标签和内部参数名两种身份。比如func greet(person name: String, from city: String) { print(欢迎\(name)来自\(city)) } greet(person: 小明, from: 北方某城)调用时能看到外部标签person和from句子读起来非常自然函数内部则用内部参数名name和city书写逻辑。如果声明时只写一个名字那么它同时承担外部和内部标签。如果不想让调用方写外部标签可以用下划线func add(_ a: Int, _ b: Int) - Int { return a b } let sum add(3, 5)这种写法在传入“动作”时很常见后面你会看到很多闭包参数都这样设计。Swift在可读性上的投入是它跟C系语言差异最大的一块函数标签只是其中一角。返回值方面也值得提醒如果函数体只有一行表达式Swift允许省略return这是5.1之后的特性。初学阶段建议老老实实写return等语法熟练了再按团队风格调整否则容易把隐式返回和普通表达式搞混。6. 集合类型初探Array、Dictionary、Set的选择直觉6.1 三种集合的关键差异Swift标准库里最常用的三种集合是Array、Dictionary、Set。它们解决的问题很清晰Array有序、可重复按下标访问。Dictionary键值对映射按键快速查找。Set无序、不可重复用于判断“是否存在”和集合运算。选型时用一个简单的判断标准需要按位置取东西用Array需要按key取value用Dictionary只需要知道元素在不在集合里或者想做交集并集用Set。集合顺序性重复元素典型场景Array有序允许列表、按索引访问Dictionary无序key唯一配置映射、快速查找Set无序不允许去重、成员判断、交并集声明方式的区别也要记住let nums [1, 2, 3, 4] let dict [name: 小明, age: 18] let set: SetInt [1, 2, 3, 1, 2] // 实际内容是1,2,3Set需要显式声明类型因为编译器没法从数组字面量推断出你想要集合类型。空数组、空字典同理必须给出类型比如let emptyDict: [String: Int] [:]。Set的去重特性在“标签系统”“排除重复ID”等场景非常好用初学者往往把它忘在脑后遇到问题只会无脑用Array然后手写contains判断性能和逻辑都吃亏。6.2 Dictionary取值为什么会返回Optional字典下标访问的一个关键特性是返回值为Optional。因为给定的键可能不存在Swift必须有能力表达这种缺失。let scores [math: 98, english: 92] let math scores[math] // Int?值为Optimal.some(98) let physics scores[physics] // Int?值为nil新手最容易栽在这里直接拿字典取下标然后用编译器报错提示未解包。正确姿势仍然是guard let或if let绑定正好把上一章Optional的知识串起来了。另外字典的键必须是Hashable的。String、Int、Double、Bool这些基础类型天然满足自定义类型如果想当键要主动实现Hashable协议这属于后面进阶的话题先知道有这么一回事就行。字典还有一个常用操作值得记住更新值可以用updateValue(_:forKey:)它会返回旧值且返回类型是Optional——因为这个键之前可能没有值。看到Optional就条件反射地做安全处理这应该是你学完上一章之后的本能。6.3 值类型带来的拷贝行为改动集合时发生了什么集合类型也是值类型。这意味着把一个数组赋值给另一个变量两个变量就是两个独立数组修改其中一个不影响另一个var a [1, 2, 3] var b a b.append(4) print(a) // [1, 2, 3] print(b) // [1, 2, 3, 4]这个行为在初学阶段特别容易踩坑尤其是从Java/Python转过来的人那些语言里list/array是引用语义直接赋值会让两边指向同一个底层对象。Swift为了性能底层采用写时复制语法上完全符合值语义真正修改时才发生拷贝。从学习者视角你只需要坚信一条值类型的赋值是“各管各的”。同理把数组传给函数函数内部再怎么append、remove外面的数组依然不变。如果确实需要函数修改外面的数组得用inout参数或者让函数返回一个新数组。初学阶段我建议你优先写纯函数——输入参数、返回结果、不修改外部状态。这个习惯在团队协作里也是最容易受好评的编码风格。7. 这一部分学完给自己安排一个能验证的小目标7.1 建议练手题目与完成标准说再多语法不亲手写一遍都是空中楼阁。Swift基础第一部分的练手题目我建议从下面三个里挑一个做。温度转换器输入摄氏度输出华氏度。要求用函数封装参数和返回值写清楚类型。完成标准能处理负数、小数输出排版干净。这个题能把变量、数值转换、函数调用全串起来。猜数字游戏程序随机产生一个1到100的整数循环接收用户输入提示太大或太小直到猜中。完成标准输入是字符串必须用Optional相关处理来转换数值循环和条件分支至少各用两种写法。这个题是控制流和Optional的综合训练。简单通讯录用字典存一组姓名和电话支持按姓名查找、遍历打印、添加新联系人。完成标准查找时联系人不存在不会崩溃能输出友好提示。这个题覆盖字典、遍历、函数设计。这些题目的共同点是不涉及界面纯Swift逻辑在Playground里就能直接跑。它们恰好覆盖了变量、类型、Optional、控制流、函数、集合这几个章节的全部知识点。做完任何一个都比单纯看完这篇内容更有价值。7.2 如果卡住了优先看这几个方向练题卡住很正常但很多卡住的人有个共性不知道报错在提示什么。遇到编译错误建议按这个顺序排查。第一步看是不是Optional问题——最常见的是Optional没解包或者解包方式不匹配。第二步看类型是否一致——把Int传给需要Double的参数或者把字符串直接拿来当数字计算这类问题一眼就能看出来。第三步检查边界值和循环条件——很多bug不是语法问题是边界写错了。第四步如果报错信息很长优先看最后一个“Cannot convert value”或“Expected expression”类型的提示那往往是真正的根源前面的报错标记很多时候只是连锁反应出的次生错误。这套排查思路熟练之后调试速度比背十个API都有用。7.3 学习方法建议别急着追新特性Swift语言本身迭代得很快每年都有新版本、新特性发布。但对处在iOS学习路线前期的你而言把基础语法和设计哲学吃透远比追新特性重要。我在日常交流中观察到的普遍情况是能把let/var、Optional、值类型这三大观念真正内化的人后面学SwiftUI、并发框架都轻松很多反过来急着看一堆高级特性、但基础观念没建立的人一到自己上手写代码就原形毕露。下一阶段可以接着学更多集合操作像map、filter、reduce、结构体与类、枚举、闭包以及协议的基础概念。这些是Swift基础第二部分的内容。现阶段最重要的事就是把我上面说的几个练手题目真正做完并且在每个题里刻意用上guard let和let优先这两个习惯。练完再回头看这篇内容你会发现很多之前觉得抽象的概念突然都变成了理所当然的设计。
阅读完成 · 觉得有帮助?