Swift语法精讲:从基础到进阶——一个老码农的碎碎念

温柔云端
2025-12-12 15:58
阅读 456

上个月地铁10号线上,我靠着扶手眯着眼刷Swift文档,旁边一个实习生模样的小伙子探头看了眼我的屏幕,小声问:“哥,您这年纪还写iOS啊?”
我当时差点把手机扔他脸上——35岁怎么了?老子还在用Swift给公司搞双11大促首页呢!
不过说真的,自从去年被领导“建议”接手公司那个快十年的老iOS项目后,我才真正重新拾起Swift。以前总觉得Obj-C才是正统,结果现在看那些.m文件就像看甲骨文。

今天这篇不是什么官方教程,纯粹是一个被deadline追着跑、靠ChatGPT续命、每天通勤两小时的老程序员在实战中踩坑又爬出来的经验总结。如果你也正在被产品经理催着加“再改一版UI就上线”的需求,或者刚被App Store审核拒了三次,希望下面这些内容能帮你省点头发。


为啥突然要深挖Swift?

这事得从去年双11说起。我们那个老项目用的是Swift 4.x,UI还是纯Storyboard拖出来的,测试同学每次提Bug都说“这页面转场卡得像PPT”。领导拍板:重构!用SwiftUI重做核心流程!

我内心OS:你咋不上天?但嘴上只能回“好的收到”。于是开始了白天改需求、晚上啃Swift文档的日子。最开始连@State@Binding都分不清,写个列表滚动直接内存爆炸,Xcode报错EXC_BAD_ACCESS时真想砸电脑。

但慢慢摸下来发现,Swift这语言,越用越香。尤其是配合Rust最近学的ownership思想(别笑,我确实在同时啃两个新东西),对值类型、不可变性这些概念理解更深了。


基础不牢,地动山摇:几个你以为会其实不会的点

1. Optional 到底是个啥?

新手总以为Optional就是“可能为nil”,但没理解它本质是个枚举

enum Optional<Wrapped> {
    case none
    case some(Wrapped)
}

这意味着你根本不能直接拿String?去拼字符串,否则编译器直接给你红脸。以前我总写:

let name: String? = "老张"
print("Hello, \(name)") // 编译报错!

后来才学会用??if letguard let这些安全解包姿势。现在我的代码里基本看不到强制解包!了——除非是IBOutlet,毕竟Storyboard绑定的东西不可能为nil(吧?)。

2. 值类型 vs 引用类型:别再乱传class了!

Swift里Struct是值类型,Class是引用类型。这点在多线程或状态管理时特别重要。比如你有个用户模型:

struct User {
    var name: String
    var avatarURL: URL
}

// 在ViewModel里修改
var currentUser = User(name: "老王", avatarURL: someURL)
currentUser.name = "老李" // 不会影响其他持有该User的地方

但如果你用class:

class User {
    var name: String
    init(name: String) { self.name = name }
}

let userA = User(name: "老王")
let userB = userA
userB.name = "老李"
print(userA.name) // 输出"老李"!因为指向同一个实例

在SwiftUI里,强烈建议Model用Struct。不然状态更新会乱套,View刷新莫名其妙失效。我上周就因为一个class model导致列表选中状态全错,debug到凌晨两点。


进阶玩法:让代码更Swift-y

1. Result<T, Error> + async/await:告别回调地狱

以前网络请求嵌套三层回调,代码长得像意大利面条。现在用async/await,清爽多了:

func fetchUserProfile() async throws -> User {
    let (data, _) = try await URLSession.shared.data(from: profileURL)
    return try JSONDecoder().decode(User.self, from: data)
}

// 调用
Task {
    do {
        let user = try await fetchUserProfile()
        DispatchQueue.main.async {
            self.currentUser = user
        }
    } catch {
        print("加载失败: \(error)")
    }
}

注意:别忘了切回主线程更新UI!虽然SwiftUI自动处理部分刷新,但涉及复杂状态还是手动dispatch保险。

2. Property Wrapper:自己造轮子也挺爽

除了系统提供的@State@Published,你也可以自定义。比如我写了个@UserDefaultsBacked,自动同步到本地存储:

@propertyWrapper
struct UserDefaultsBacked<Value> {
    let key: String
    let defaultValue: Value

    var wrappedValue: Value {
        get {
            return UserDefaults.standard.object(forKey: key) as? Value ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

// 使用
@UserDefaultsBacked(key: "isDarkMode", defaultValue: false)
var isDarkMode: Bool

这样在Settings页面切换主题,其他View自动响应,不用再写一堆通知或者单例。


实战避坑指南:血泪换来的经验

审核被拒?可能是这些Swift细节没注意

  1. 隐私描述缺失:如果你用了CLLocationManager,即使只是测试,也要在Info.plist里加上NSLocationWhenInUseUsageDescription,否则App Store直接拒。
  2. 后台模式滥用:别随便开background fetch,除非真有推送同步需求。我们有一次因为加了个无意义的后台任务,被审核团队问了三天。
  3. Swift包兼容性:用Swift Package Manager引入第三方库时,注意最低iOS版本。有些库只支持iOS 13+,但你项目支持iOS 11,Xcode不报错,但上传时Archive会失败。

性能陷阱:别让Swift“优雅”拖慢App

  • 避免在View body里做计算:SwiftUI的body会被频繁调用,如果在里面写map.filter.sort,列表滑动直接掉帧。

    // 错误示范
    var body: some View {
        List(items.filter { $0.isFavorite }) { item in ... }
    }
    
    // 正确做法:提前计算好
    private var favoriteItems: [Item] {
        items.filter { $0.isFavorite }
    }
    
  • 慎用@StateObject vs @ObservedObject:前者只在View首次创建时初始化,后者每次父View刷新都会重建。用错会导致ViewModel重复请求数据。


资源推荐:别再瞎搜了

类型 推荐 说明
官方文档 Swift.org 语法权威,但有点干
中文社区 SwiftGG翻译组 很多高质量译文
视频教程 Sean Allen的YouTube频道 实战向,幽默风趣
开源项目 Apollo iOS 看大厂怎么组织Swift项目
调试工具 InjectionIII 热重载Swift代码,省去反复编译

我自己最常用的是Swift Playground + ChatGPT组合。遇到奇怪语法,直接扔给Claude:“用Swift写个带泛型的缓存类,支持LRU淘汰”,5秒出原型,再自己调整。效率比翻Stack Overflow高多了(别打我,我知道应该自己思考……)


最后几句心里话

写Swift这几年,最大的感悟是:语言只是工具,解决问题才是目的
我见过用Swift写出屎山代码的,也见过用Obj-C写出优雅架构的。关键不是语法多炫酷,而是能不能让App稳定、让用户流畅、让自己下班。

上周五晚上,我终于把重构后的首页提交TestFlight,产品经理发来消息:“这次滑动真的丝滑!” 那一刻,觉得通勤一小时、加班到九点都值了。

所以,别管35岁还是25岁,只要键盘还在敲,代码还能跑,咱们就还是程序员。
Swift也好,Rust也罢,学就完了。反正,头发已经不多了,不如多写点好代码。


PS:如果你也在北京挤地铁写代码,评论区留个言,说不定哪天咱俩在国贸站撞见,还能一起吐槽今天的CI又挂了 😅

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝