01. 类和结构体的区别
Swift 中类和结构体都能定义属性和方法,但关键区别:类是引用类型(赋值时拷贝引用),结构体是值类型(赋值时拷贝整个数据)。这意味着结构体在多线程中更安全,类是共享的。另外类支持继承,结构体不支持。苹果建议优先用结构体。
swift
// 结构体 - 值类型
struct Point {
var x: Double
var y: Double
mutating func moveBy(x: Double, y: Double) {
self.x += x
self.y += y
}
}
var p1 = Point(x: 0, y: 0)
var p2 = p1 // 完整拷贝
p2.x = 10
print(p1.x) // 0 - p1 没变
// 类 - 引用类型
class Person {
var name: String
init(name: String) { self.name = name }
}
var person1 = Person(name: "小明")
var person2 = person1 // 拷贝引用
person2.name = "小红"
print(person1.name) // 小红 - person1 也变了Swift 中能不用类就不用类,struct + enum + protocol 的组合完全可以实现大部分需求。
02. 继承和重写
Swift 继承用冒号语法:class Dog: Animal {}。子类可以重写父类的方法、属性和下标,用 override 关键字。final 阻止重写。super 关键字调用父类实现。override 是强制标注的,编译器会检查你真的在重写一个存在的方法,不会意外创建新方法。
swift
class Animal {
var name: String
init(name: String) {
self.name = name
}
func speak() -> String {
return "..."
}
}
class Dog: Animal {
var breed: String
init(name: String, breed: String) {
self.breed = breed
super.init(name: name)
}
override func speak() -> String {
return super.speak() + " 汪汪"
}
}
let dog = Dog(name: "旺财", breed: "金毛")
print(dog.speak()) // ... 汪汪override 是编译安全检查,防止你打错方法名或父类方法改了签名导致的 bug。
03. 协议 Protocol
Swift 的协议非常强大,类似其他语言的接口但功能更多。可以定义方法、属性(只读或读写)、甚至可选方法(@objc 协议)。一个类型可以遵循多个协议:struct MyType: ProtoA, ProtoB {}。协议扩展(extension)可以提供默认实现,这就是 Swift 的面相协议编程。
swift
protocol Identifiable {
var id: String { get set }
func identify() -> String
}
// 协议扩展 - 提供默认实现
extension Identifiable {
func identify() -> String {
return "ID: \(id)"
}
}
struct User: Identifiable {
var id: String
var name: String
// identify 已经有默认实现了
}
let user = User(id: "001", name: "小明")
print(user.identify()) // ID: 001
// 协议作为类型
func printIdentifier(_ item: Identifiable) {
print(item.identify())
}Swift 是面相协议编程(POP)的语言,通过协议加扩展可以实现类似多重继承的代码复用。
04. 属性观察器和懒加载
willSet 在属性即将被修改时触发(可以拿到新值),didSet 在修改完成后触发(可以拿到旧值)。这两个观察器在初始化时不触发。lazy var 延迟初始化,第一次访问时才创建,适合创建开销大或依赖其他属性的变量。
swift
class Temperature {
var celsius: Double = 0 {
willSet(newTemp) {
print("即将变为 \(newTemp)度")
}
didSet(oldTemp) {
print("从 \(oldTemp)度变为 \(celsius)度")
if celsius > 100 {
print("警告:温度超过100度!")
}
}
}
// 懒加载
lazy var fahrenheit: Double = {
return celsius * 9 / 5 + 32
}()
}
let t = Temperature()
t.celsius = 25 // 触发 willSet 和 didSetdidSet 做更新后的校验或联动刷新比手动每次都调方便得多。
05. 扩展 Extension
扩展可以给已有的类、结构体、枚举、协议添加新功能,而且不需要访问源码。可以添加计算属性(不能加存储属性)、方法、新的构造器、让类型遵循协议等。扩展很常用来拆分功能模块、为系统类型添加便利方法。
swift
// 给 Double 添加扩展
extension Double {
var km: Double { return self * 1000.0 }
var cm: Double { return self / 100.0 }
}
let distance = 5.0.km // 5000.0
// 给 Array 添加安全访问
extension Array {
subscript(safe index: Int) -> Element? {
return indices.contains(index) ? self[index] : nil
}
}
let arr = [1, 2, 3]
print(arr[safe: 10] ?? "不存在") // 不存在
// 通过扩展遵循协议
extension User: CustomStringConvertible {
var description: String {
return "\(name) (\(id))"
}
}扩展不能包含存储属性,但可以用关联对象技术绕过,不过一般没必要。
知识测验
第 1/4 题正确 0
Swift 中结构体和类最核心的区别?
下一节
下一节 异步编程