本篇目标
理解类与结构体的定义与使用,掌握属性、方法、初始化器、继承,弄清值类型与引用类型的区别,能根据场景选择类或结构体。
一、类与结构体基础
定义结构体:
struct Point {
var x: Double
var y: Double
}
var p1 = Point(x: 1.0, y: 2.0)
print(p1.x) // 1.0定义类:
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}
let person = Person(name: "Tom", age: 25)
print(person.name) // Tom基本区别:
特性 | 结构体 struct | 类 class |
|---|---|---|
类型 | 值类型 | 引用类型 |
继承 | 不支持 | 支持 |
初始化器 | 自动生成成员初始化器 | 需要手写 init |
析构器 | 无 | 有 deinit |
引用计数 | 无 | 有 ARC |
赋值/传参 | 拷贝 | 引用同一实例 |
二、属性
存储属性
struct Student {
var name: String
var age: Int
}常量属性
struct Student {
let id: Int
var name: String
}let属性初始化后不可修改。结构体的
let实例,其属性都不可修改。
计算属性
不直接存储值,通过 get/set 计算。
struct Rectangle {
var width: Double
var height: Double
var area: Double {
return width * height
}
}
let rect = Rectangle(width: 3, height: 4)
print(rect.area) // 12.0带 set 的计算属性:
struct Square {
var side: Double
var area: Double {
get {
return side * side
}
set {
side = sqrt(newValue)
}
}
}
var square = Square(side: 2)
print(square.area) // 4.0
square.area = 9
print(square.side) // 3.0只读计算属性简写:
var area: Double {
width * height
}属性观察器
willSet 在赋值前调用,didSet 在赋值后调用。
class StepCounter {
var steps: Int = 0 {
willSet {
print("即将设置为 \(newValue)")
}
didSet {
print("从 \(oldValue) 变为 \(steps)")
}
}
}
let counter = StepCounter()
counter.steps = 100
// 即将设置为 100
// 从 0 变为 100注意:
属性观察器不适用于计算属性。
willSet使用newValue,didSet使用oldValue。
类型属性
用 static 声明,属于类型本身。
struct AppInfo {
static let name = "MyApp"
static var version = "1.0"
}
print(AppInfo.name) // MyApp类中可用 `class` 修饰可被重写的类型属性:
class Animal {
class var category: String {
return "动物"
}
}三、方法
实例方法
class Counter {
var count = 0
func increment() {
count += 1
}
func increment(by amount: Int) {
count += amount
}
func reset() {
count = 0
}
}修改值类型的方法
结构体和枚举的实例方法要修改属性时,需要加 mutating。
struct Point {
var x = 0.0
var y = 0.0
mutating func moveBy(x deltaX: Double, y deltaY: Double) {
x += deltaX
y += deltaY
}
}
var point = Point()
point.moveBy(x: 1, y: 2)
print(point.x, point.y) // 1.0 2.0类型方法
用 static 或 class 声明。
struct MathHelper {
static func square(_ x: Int) -> Int {
return x * x
}
}
print(MathHelper.square(5)) // 25类中可重写的类型方法:
class Base {
class func info() -> String {
return "Base"
}
}
class Sub: Base {
override class func info() -> String {
return "Sub"
}
}四、初始化器
结构体成员初始化器
结构体会自动生成成员初始化器。
struct Point {
var x: Double
var y: Double
}
let p = Point(x: 1, y: 2)自定义初始化器后,自动成员初始化器会失效,除非写在 extension 中。
struct Point {
var x: Double
var y: Double
init(x: Double, y: Double) {
self.x = x
self.y = y
}
}类的初始化器
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
}默认初始化器:
如果所有属性都有默认值,类会获得默认初始化器。
class Settings {
var theme = "light"
var fontSize = 14
}
let settings = Settings()指定初始化器与便利初始化器
指定初始化器:负责初始化所有属性,调用父类初始化器。
便利初始化器:用 convenience 声明,必须调用本类的指定初始化器。
class Person {
var name: String
var age: Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
convenience init(name: String) {
self.init(name: name, age: 0)
}
}
let p1 = Person(name: "Tom") // age 默认 0
let p2 = Person(name: "Jerry", age: 20)可失败初始化器
用 init? 声明,可能返回 nil。
struct Temperature {
var celsius: Double
init?(celsius: Double) {
if celsius < -273.15 {
return nil
}
self.celsius = celsius
}
}
let t1 = Temperature(celsius: 25) // 成功
let t2 = Temperature(celsius: -300) // nil析构器
类可以定义 deinit,在实例被释放时调用。
class FileHandler {
var path: String
init(path: String) {
self.path = path
print("打开文件:\(path)")
}
deinit {
print("关闭文件:\(path)")
}
}五、继承
类可以继承另一个类,获取父类的属性和方法。
class Animal {
var name: String
init(name: String) {
self.name = name
}
func makeSound() {
print("动物发出声音")
}
}
class Dog: Animal {
override func makeSound() {
print("汪汪")
}
func fetch() {
print("\(name) 在捡球")
}
}
let dog = Dog(name: "旺财")
dog.makeSound() // 汪汪
dog.fetch() // 旺财 在捡球重写:
方法、属性、下标都可以重写。
重写需要用
override关键字。用
super调用父类实现。
class Cat: Animal {
override func makeSound() {
super.makeSound()
print("喵喵")
}
}防止重写:
用 final 标记。
final class FinalClass {
// 不能被继承
}六、值类型与引用类型
值类型(结构体):
struct Point {
var x: Int
var y: Int
}
var p1 = Point(x: 1, y: 2)
var p2 = p1 // 拷贝
p2.x = 10
print(p1.x) // 1,p1 不受影响
print(p2.x) // 10引用类型(类):
class Point {
var x: Int
var y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
var p1 = Point(x: 1, y: 2)
var p2 = p1 // 引用同一实例
p2.x = 10
print(p1.x) // 10,p1 也被修改判断是否同一实例:
if p1 === p2 {
print("同一个实例")
}选择建议:
场景 | 推荐 |
|---|---|
数据模型、值语义 | 结构体 |
需要继承、共享状态 | 类 |
小型、简单数据结构 | 结构体 |
需要引用计数、生命周期管理 | 类 |
SwiftUI 视图 | 结构体 |
ViewModel、Manager | 类 |
七、避坑指南
结构体是值类型:赋值、传参都会拷贝,注意性能。
类是引用类型:多个变量指向同一实例,修改会互相影响。
mutating 不能漏:结构体方法修改属性时必须加。
类必须先初始化所有属性:否则编译报错。
继承要慎用:优先使用组合。
循环引用:类之间相互持有强引用会导致内存泄漏,使用
weak或unowned。final 提升性能:不需要继承的类加
final,编译器可优化。
八、检查清单
[ ] 能定义结构体和类
[ ] 理解存储属性、计算属性、属性观察器
[ ] 会使用实例方法与类型方法
[ ] 理解 mutating 的作用
[ ] 会写初始化器与便利初始化器
[ ] 理解继承与重写
[ ] 能区分值类型与引用类型
[ ] 能根据场景选择类或结构体