Swift 进阶之旅:探索类与结构体的魅力(下)
2024-01-09 00:45:13
从基础到高级,逐步掌握 Swift 类与结构体
在前一篇文章中,我们初步了解了 Swift 中的类与结构体,并学习了如何创建和使用它们。在本文中,我们将继续深入探索这些强大工具的更多特性,让您对 Swift 的理解更上一层楼。
异变方法:可修改值的奥秘
我们都知道类与结构体都可以定义方法,但有一点区别,值类型属性不能被自身的实例方法所修改。这似乎有些限制,但 Swift 提供了一种巧妙的方法来解决这个问题——添加 mutating 。
当在一个值类型的方法中使用 mutating 关键字时,它就允许该方法修改自身的属性。这在某些情况下非常有用,例如,在一个结构体中定义一个方法来更新其属性值。
例如:
struct Point {
var x: Int
var y: Int
mutating func moveBy(dx: Int, dy: Int) {
x += dx
y += dy
}
}
var point = Point(x: 10, y: 20)
point.moveBy(dx: 5, dy: -3)
print(point) // 输出:Point(x: 15, y: 17)
存储属性:数据之源泉
存储属性是用来存储数据的变量,它们可以是实例属性或类属性。实例属性属于类的实例,而类属性属于整个类。
在 Swift 中,存储属性的声明方式非常简单,只需使用 var 或 let 关键字,后跟属性名称和类型即可。例如:
class Person {
var name: String
let age: Int
}
struct Car {
var model: String
var year: Int
}
属性观察器:数据变更的监视者
属性观察器允许您在属性值发生变化时执行某些操作。Swift 提供了两种属性观察器:willSet 和 didSet。
- willSet 观察器会在属性值将要发生变化时触发。
- didSet 观察器会在属性值发生变化后触发。
例如:
class Person {
var name: String {
willSet {
print("Name will be changed to \(newValue)")
}
didSet {
print("Name has been changed to \(name)")
}
}
}
var person = Person(name: "John")
person.name = "Mary"
上面的代码会输出:
Name will be changed to Mary
Name has been changed to Mary
计算属性:灵活获取数据
计算属性允许您根据其他属性的值来计算出一个新的值。计算属性没有存储空间,它们的值是通过计算得到的。
例如:
struct Rectangle {
var width: Double
var height: Double
var area: Double {
return width * height
}
}
var rectangle = Rectangle(width: 10.0, height: 5.0)
print(rectangle.area) // 输出:50.0
类方法:属于整个类的函数
类方法是属于整个类的函数,它们可以通过类名直接调用,而无需创建类的实例。
例如:
class Person {
static func createPerson(name: String, age: Int) -> Person {
return Person(name: name, age: age)
}
}
let person = Person.createPerson(name: "John", age: 30)
静态属性:共享的数据
静态属性是属于整个类的属性,它们与类方法一样,可以通过类名直接访问。
例如:
class Person {
static var species = "Homo sapiens"
}
print(Person.species) // 输出:Homo sapiens
继承:代码复用的利器
继承允许您创建新的类,这些类可以从现有的类继承属性和方法。这是一种非常强大的代码复用技术。
例如:
class Vehicle {
var make: String
var model: String
var year: Int
init(make: String, model: String, year: Int) {
self.make = make
self.model = model
self.year = year
}
}
class Car: Vehicle {
var numWheels: Int
init(make: String, model: String, year: Int, numWheels: Int) {
super.init(make: make, model: model, year: year)
self.numWheels = numWheels
}
}
let car = Car(make: "Toyota", model: "Camry", year: 2020, numWheels: 4)
print(car.make) // 输出:Toyota
print(car.model) // 输出:Camry
print(car.year) // 输出:2020
print(car.numWheels) // 输出:4
多态:代码的可扩展性
多态性是指对象能够以不同的形式存在。在 Swift 中,多态性通过继承和方法重写来实现。
例如:
class Shape {
func area() -> Double {
fatalError("This method must be overridden")
}
}
class Rectangle: Shape {
var width: Double
var height: Double
init(width: Double, height: Double) {
self.width = width
self.height = height
}
override func area() -> Double {
return width * height
}
}
class Circle: Shape {
var radius: Double
init(radius: Double) {
self.radius = radius
}
override func area() -> Double {
return π * radius * radius
}
}
let shapes: [Shape] = [
Rectangle(width: 10.0, height: 5.0),
Circle(radius: 5.0)
]
for shape in shapes {
print(shape.area())
}
上面的代码会输出:
50.0
78.53981633974483
访问控制:数据的私密性
访问控制允许您控制对属性和方法的访问权限。Swift 提供了五种访问控制级别:
- private :只有在定义属性或方法的类中才能访问。
- internal :只有在同一个模块中才能访问。
- public :可以在任何地方访问。
- open :可以在任何地方访问,并且可以被子类重写。
- fileprivate :只有在定义属性或方法的文件中才能访问。
例如:
class Person {
private var name: String
internal var age: Int
public func sayHello() {
print("Hello, my name is \(name)")
}
open func introduce() {
print("I am \(name), and I am \(age) years old")
}
fileprivate func printName() {
print(name)
}
}
值传递与引用传递:数据的拷贝
在 Swift 中,值传递是默认的数据传递方式。这意味着当一个值被传递给一个函数或另一个变量时,会创建一个该值的副本。
引用传递则不同,它会传递一个指向数据的指针,而不是数据的副本。这意味着对该指针所指向的数据所做的任何修改都会反映在原始数据上。
Swift 中只有结构体是值类型,而类是引用类型。这意味着当您将一个结构体传递给一个函数或另一个变量时,会创建一个该结构体的副本,而当您将一个类传递给一个函数或另一个变量时,会传递一个指向该类的指针。
例如:
struct Point {
var x: Int
var y: Int
}
class Person {
var name: String
var age: Int
}
var point1 = Point(x: 10, y: 20)
var point2 = point1
point2.x = 30
print(point1) // 输出:Point(x: 10, y: 20)
print(point2) // 输出:Point(