请写一篇关于【Swift入门教程:iOS开发第一步】的技术文章
去年十月的一个周五晚上,我坐在南山区白石洲那间月租3500的单间里,窗外是深南大道永不熄灭的霓虹。老婆已经睡了,我偷偷把MacBook音量调到最低,一边啃着冷掉的猪脚饭,一边在Xcode里敲下第一行 print("Hello, World!")。
那一刻,我差点哭出来——不是因为感动,而是因为焦虑。
我,一个干了三年测试、月薪15k、连Swift语法都分不清Optional和Guard的“老”程序员,居然真的决定转行做iOS开发了。
起因:一次被爬虫“打脸”的经历
事情得从三个月前说起。我在一家做电商SaaS的小公司做自动化测试工程师,日常工作就是写Python脚本跑UI自动化、维护Jenkins流水线、偶尔帮产品查个数据。日子过得安稳,但总觉得缺了点什么。
那天下午,产品经理小李冲进测试组:“兄弟们,竞品上新了个功能,能不能搞个爬虫扒一下他们接口参数?”
我说:“没问题,Python requests + BeautifulSoup,半小时搞定。”
结果呢?
人家App用了双向SSL证书校验,请求头带动态Token,还有混淆的Protobuf协议。我折腾了一天,最后只抓到一堆加密的二进制包。而隔壁iOS开发小王,轻描淡写地说了一句:“我Hook一下NSURLSessionDelegate就能拿到原始请求,你要不试试?”
那一刻,我站在茶水间,手里端着刚泡好的雀巢咖啡,突然意识到:测试再深入,也只是在别人搭好的舞台上跳舞;而开发,才是那个搭舞台的人。
回家路上,我跟老婆说:“我想学Swift,转iOS开发。”
她沉默了几秒,问:“那工资能涨吗?”
我说:“应该能吧……至少22k起步?”(后来证明这预判还挺准)
第一步:安装Xcode,就卡了我两小时
别笑,真的。
我用的是2018款MacBook Pro,系统还是Catalina。打开App Store搜Xcode,点击下载——进度条走到98%突然报错:“无法验证开发者”。
重启、清缓存、换Apple ID、甚至跑到华强北找人重装系统……最后发现是因为我之前为了省空间删了Command Line Tools。
这事儿让我明白了一个道理:iOS开发的第一道门槛,根本不是代码,而是环境。
等Xcode终于跑起来,新建一个“App”项目,选Swift、Storyboard、iPhone 14模拟器……点击Run,屏幕上弹出一个空白页面,左上角写着“Hello, World!”。
我盯着它看了五分钟,心里默默OS:就这?这就是传说中的原生开发?
但下一秒,我改了Label的文字,重新Run——界面立刻变了。
那种“所见即所得”的即时反馈感,是写Python脚本时永远体会不到的爽。
案例驱动:做个天气查询App练手
既然要学,那就不能光看文档。我给自己定了个小目标:一周内做出一个能用的天气App。
第一天:UI搭建
拖拽两个Label、一个TextField、一个Button到Storyboard里。
给Button绑定IBAction,TextField绑定IBOutlet。
点击按钮,打印输入的城市名——搞定!
但问题来了:怎么联网?
第二天:网络请求初体验
我翻出以前写爬虫的经验,心想:“不就是发个GET请求嘛,跟requests.get()有啥区别?”
结果Swift的URLSession把我整懵了。
回调嵌套、Result类型、主线程更新UI……我写了半天,App一跑就崩溃,报错:“Main Thread Checker: UI API called on a background thread”。
原来,在iOS里,所有UI操作必须在主线程执行。而网络请求默认在后台线程。你得手动切回来:
DispatchQueue.main.async {
self.weatherLabel.text = "当前温度: \(temp)°C"
}
那一刻,我突然理解了为什么以前开发同事总说“别在子线程改UI”——这真不是矫情,是会崩的。
第三天:解析JSON
天气API返回的是JSON,结构大概是这样:
{
"city": "深圳",
"temperature": 28,
"condition": "多云"
}
在Python里,json.loads()一行搞定。但在Swift里,得先定义一个Struct,还得符合Codable协议:
struct WeatherResponse: Codable {
let city: String
let temperature: Int
let condition: String
}
然后用JSONDecoder()去解析。
一开始我把字段名拼错了(比如写成temprature),App直接Crash,控制台吐出一串keyNotFound错误。
调试了半小时才发现是少了个“e”。
静态类型语言的好处是编译时报错,坏处是你得为每一个字母负责。
从爬虫思维到开发思维:我的认知转变
作为一个前爬虫工程师,我习惯“拿到数据就完事”。但在开发App时,我发现要考虑的东西太多了:
- 用户体验:用户输错城市怎么办?网络超时怎么提示?要不要加个Loading动画?
- 状态管理:数据加载中、成功、失败——三种状态都要有对应UI。
- 内存安全:闭包里引用self会不会造成循环引用?得加
[weak self]。 - 权限申请:虽然这个App不需要定位,但如果要用GPS,就得提前在Info.plist里声明。
这些,都是写爬虫时不用操心的。
有一次,我为了偷懒,直接把API Key写死在代码里。结果上传GitHub后,第二天就被机器人扫到,Key被滥用,账单暴涨。
团队里的iOS老哥拍了拍我肩膀:“兄弟,敏感信息放本地配置文件,或者用Environment Variable,别commit到仓库。”
开发不是写功能,是构建一个可维护、可扩展、安全的系统。这句话,我现在才真正懂。
开发心得:那些没人告诉你的坑
Storyboard vs SwiftUI
我一开始用Storyboard,因为可视化。但后来发现多人协作时容易冲突。现在新项目都推SwiftUI了,声明式语法更优雅,但学习曲线陡。建议新手先用Storyboard理解MVC,再过渡到SwiftUI。模拟器不是真机
在模拟器跑得好好的App,装到旧款iPhone上直接卡死。原因是模拟器性能太强,掩盖了内存泄漏和主线程阻塞问题。一定要真机测试!别迷信教程
网上很多Swift教程还是iOS 12时代的,用的还是URLSession.shared.dataTask的老写法。现在推荐用async/await(iOS 15+):do { let (data, _) = try await URLSession.shared.data(from: url) // 处理数据 } catch { print("请求失败: $error)") }这种写法清爽多了,但前提是你的App最低支持iOS 15。
测试也是开发的一部分
虽然我是测试出身,但做开发后才发现:单元测试不是QA的事,是开发者自己的安全网。现在我每写一个ViewModel,都会配套写XCTest用例。跑通那一刻,比喝冰美式还提神。
转型后的现实:从15k到22k,但代价是头发
今年三月,我跳槽到了南山科技园一家做健康IoT的公司,职位是初级iOS开发,月薪22k。
面试官问我:“你之前是测试,为什么转开发?”
我说:“因为我发现,与其天天想着怎么绕过别人的逻辑,不如自己亲手造轮子。”
他笑了,说:“欢迎加入造轮子联盟。”
现在的我,依然住在白石洲,房租涨到了3800。每天加班到九点,回家还要看WWDC视频补课。但每当看到App Store里自己写的App有了真实用户,收到“这个功能真好用”的评论时,那种成就感,是以前跑通一百个自动化脚本都比不了的。
给想入门Swift的朋友几点建议
- 别怕从零开始。我30岁转行,照样能行。年龄不是问题,行动力才是。
- 动手做项目。哪怕只是一个Todo List,也比抄十遍教程强。
- 善用Apple官方文档。Swift.org和Developer.apple.com的Guides写得比大多数付费课程都清楚。
- 加入社区。深圳有SwiftGG翻译组、有各种Meetup,别一个人闷头搞。
- 保持测试思维。作为前测试,我反而更注重边界条件和异常处理——这是我们的优势。
最后一点思考
从爬虫到开发,我失去的是“快速拿到数据”的快感,得到的是“从0到1创造产品”的掌控感。
技术没有高低贵贱,但角色决定了你的视野。
测试教会我严谨,开发逼我成长。而Swift,恰好成了我跨越这条鸿沟的桥。
如果你也在人生的岔路口犹豫,不妨问问自己:
你是想一直分析别人的舞台,还是亲手搭一个属于自己的?
上周五晚上,我又在白石洲的出租屋里敲代码。这次不是Hello World,而是一个用Swift爬取招聘信息并自动投递的工具——对,我把老本行和新技能结合了。
老婆探头问:“又加班?”
我笑着说:“不,我在造轮子。”
窗外,深圳的夜依旧灯火通明。而我知道,我的代码,正在这片光里跑着。

评论 0