iOS开发入门:Swift基础知识讲解
上周五晚上十点半,我正对着Xcode里一个莫名其妙的EXC_BAD_ACCESS抓狂,突然收到读者私信:“大佬,能不能写点Swift入门的内容?看了好多资料还是云里雾罩。”
说实话,那一刻我差点回一句“我也还在学呢”,但转念一想——这不就是去年的我吗?
为什么一个外包仔要写Swift?
先简单自我介绍一下:我在一家中型互联网公司干了三年多客户端开发,主攻Android,副业接点外包项目补贴家用(你懂的,房租+奶茶+Switch游戏三座大山)。最近因为考虑跳槽,开始系统性地补iOS这块短板。毕竟现在大厂面试动不动就问“跨端能力”,光会Kotlin已经不够卷了。
上个月面了一家做海外工具类App的公司,技术面第一题就是:“用Swift实现一个线程安全的单例。” 我当场懵了,支支吾吾说“可以用GCD的dispatch_once吧?” 结果面试官笑了笑:“那是Objective-C时代的写法了。”
回家路上我就下定决心:必须把Swift啃下来。不仅为了面试,更是为了接更多平台的外包单子——你猜怎么着?上周刚谈成一个小项目,客户明确要求“只做iOS,预算5万”,我差点激动得在地铁上跳起来。
Swift不是“更简单的Java”
很多人(包括我一开始)以为Swift就是“苹果版的Java”或者“带糖衣的C#”。结果刚写两行代码就被打脸。
比如这个看似人畜无害的变量声明:
var name: String = "张三"
看起来平平无奇对吧?但如果你漏写了冒号后面的类型注解,编译器并不会报错——因为Swift有类型推断。这玩意儿在初期特别友好,但一旦涉及到泛型、协议或者可选类型嵌套,就会让你怀疑人生。
记得有一次我写了个网络请求回调:
func fetchData(completion: (Data?) -> Void)
结果调用的时候忘了处理nil情况,直接let json = try JSONSerialization.jsonObject(with: data!),上线后Crash率飙升。测试妹子追着问我:“你是不是又没判空?” —— 当时真的想原地辞职。
所以新手朋友记住:Swift的安全性是“有条件的”。它给你提供了Optional、guard let、defer这些利器,但前提是你得主动用。
几个必须搞懂的核心概念
1. 可选类型(Optional)不是摆设
这是Swift最反直觉的设计之一。很多初学者看到String?就头大,觉得“我确定这里不会为nil啊,干嘛非要包一层?”
但现实是:你永远无法100%确定外部数据不为nil。比如用户输入、网络返回、甚至系统API都可能给你nil。
正确姿势是用if let或guard let解包:
// 别再用!强制解包了!除非你确定它一定有值
if let username = UserDefaults.standard.string(forKey: "username") {
print("欢迎回来,\(username)")
} else {
showLoginView()
}
💡 小技巧:Xcode的自动补全经常会帮你生成
if let模板,别嫌啰嗦,这是在救你的命。
2. 值类型 vs 引用类型
Swift里struct是值类型,class是引用类型。听起来很学术?举个接地气的例子:
struct Point { var x: Int; var y: Int }
class Person { var name: String }
var p1 = Point(x: 1, y: 2)
var p2 = p1
p2.x = 100
print(p1.x) // 输出1!因为struct是拷贝
var person1 = Person(name: "老王")
var person2 = person1
person2.name = "小王"
print(person1.name) // 输出"小王"!因为class是引用
在实际开发中,Apple官方建议优先使用struct,因为它更安全(避免意外修改)、性能更好(栈分配),而且天然支持Copy-on-Write优化。
我之前写一个配置管理模块,图省事用了class,结果两个ViewController同时修改配置,互相污染数据,debug到凌晨三点。从此以后见到class就警惕。
3. 闭包的逃逸与非逃逸
面试高频题!简单说:如果闭包在函数返回后才执行(比如网络回调),就需要标记为@escaping。
var completionHandlers: [() -> Void] = []
func performAsyncTask(completion: @escaping () -> Void) {
completionHandlers.append(completion)
// 模拟异步操作
DispatchQueue.global().asyncAfter(deadline: .now() + 1) {
completion()
}
}
如果不加@escaping,编译直接报错。这个设计其实很贴心——它逼你在设计API时就考虑清楚生命周期问题。
学习资源推荐:别只看官方文档
我知道很多人一上来就啃《The Swift Programming Language》(俗称“Swift圣经”)。但说实话,那本书更适合当参考手册,不适合入门。
我真正入门靠的是:
| 资源类型 | 推荐内容 | 适合阶段 |
|---|---|---|
| 书籍 | 《Swift编程权威指南》(Big Nerd Ranch版) | 零基础 |
| 视频 | Stanford CS193p (2023) | 有编程基础 |
| 实战 | Ray Wenderlich教程 | 想做完整App |
特别是Stanford那门课,教授讲得贼幽默,还会吐槽Apple的设计:“Why did they name it ‘Result’? It’s so generic!”(为啥叫Result?太泛了!)
另外,强烈建议刷一刷LeetCode的Swift标签题,或者参与开源项目。我最近在GitHub上fork了一个Todo App,边改边学,比纯看书有效十倍。
面试题挑战:你能答对几道?
为了帮大家检验学习成果,我整理了几个真实面试题(都是我被问过的):
问:
weak和unowned有什么区别?
答:两者都用于解决循环引用,但weak是可选类型(自动置nil),unowned是非可选(假定对象始终存在)。慎用unowned,用错直接Crash。问:如何实现一个线程安全的计数器?
答:可以用NSLock,但更Swifty的方式是用actor(iOS 13+):actor Counter { private var count = 0 func increment() { count += 1 } func getCount() -> Int { count } }问:
map、compactMap、flatMap的区别?
答:map: 转换每个元素compactMap: 转换 + 自动过滤nilflatMap: 用于嵌套数组拍平,或处理Optional的链式调用
📌 经验之谈:面试官问基础题,往往不是考你背得多准,而是看你有没有踩过坑。回答时最好带上“我之前在项目里...”的真实案例。
最后一点真心话
写这篇文章的时候,我正在赶一个外包项目的deadline(产品经理刚刚又改了需求,说“就改一点点”)。但越是这种时候,越觉得基础扎实有多重要——如果连Optional都搞不清,怎么可能写出稳定可靠的代码?
Swift是一门“表面温柔、内里严谨”的语言。它允许你快速写出能跑的代码,但也毫不留情地惩罚懒惰和侥幸。
如果你也像我一样,是个想靠技术吃饭的普通程序员,别怕从基础开始。每天搞懂一个小概念,三个月后回头看,你会感谢现在认真敲代码的自己。
对了,文末放个小彩蛋:我在GitHub建了个仓库 Swift-Beginner-Challenges(名字随便起的),里面会持续更新新手练习题和我的解题思路。欢迎Star,也欢迎提PR一起完善!
—— 一个还在加班的斜杠程序员,于2024年春天

评论 0