一、方法(Method)
-
枚举
、结构体
、类
都可以定义实例方法
、类型方法
① 实例方法(Instance Method):通过实例对象
调用
② 类型方法(Type Method):通过类型
调用,用static
或者class
关键字定义
class Car {
static var cout = 0
init() {
Car.cout += 1
}
static func getCout() -> Int { cout }
}
let c0 = Car()
let c1 = Car()
let c2 = Car()
print(Car.getCout())
/*输出结果*/
3
-
self
① 在实例方法
中代表实例对象
② 在类型方法
中代表类型
- 在类型方法
static func getCout
中
count
等价于self.cout
、Car.self.cout
、Car.cout
mutating
-
结构体
和枚举
是值类型,默认情况下,值类型的属性不能被自身的实例方法修改
在func
关键字前加mutating
可以允许这种修改行为
此时我们使用mutating
关键字就可以修改
对于枚举
可以是这个样子的:
enum StateSwitch {
case low, middle, high
mutating func next() {
switch self {
case .low:
self = .middle
case .middle:
self = .high
case .high:
self = .low
}
}
}
@discardableResult
- 在
func
前面添加@discardableResult
,可以消除:函数调用后返回值未被使用的警告⚠️
struct Point {
var x = 0.0, y = 0.0
@discardableResult mutating
func moveBy(deltaX: Double, deltaY: Double) -> (Double, Double) {
x += deltaX
y += deltaY
return (x, y)
}
}
var p = Point()
p.moveBy(deltaX: 10.0, deltaY: 10.0)
@discardableResult
func get() -> Int {
return 10
}
get()
将方法赋值给 var \ let
- 方法可以像函数一样,赋值给一个
let
或var
class Person {
var name = "Aaron"
func changName(_ name: String) {
self.name = name
print("changName", self.name)
}
static func changeName(_ name: String) {
print("static changeName", name)
}
}
将实例方法
赋值给let
或者 var
let fn = Person.changName
let fn1 = fn(Person())
fn1("Jack")
/*输出结果*/
changName Jack
为什么要这样写呢?我们可以来查看一下fn
和fn1
的类型:
将
类型方法
赋值给let
或者var
,要加上类型,这样可以明确;如果只有一个参数也不与 实例方法
同名,可以不加类型;但是建议还是加上类型比较好。
let fn2: (String) -> () = Person.changeName
fn2("David")
/*输出结果*/
static changeName David
二、下标(subscript)
- 使用
subscript
可以给任意类型(枚举、结构体、类)增加下标功能,有些地方也翻译为:下标脚本
subscript
的语法类似于实例方法
、计算属性
,本质就是方法(函数)
class Point {
var x = 0.0, y = 0.0
subscript(index: Int) -> Double {
set {
if index == 0 {
x = newValue
} else if index == 1 {
y = newValue
}
}
get {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
}
var p = Point()
p[0] = 11.1
p[1] = 22.2
print(p.x) //11.1
print(p.y) //22.2
print(p[0]) //11.1
print(p[1]) //22.2
-
subscript
中定义的返回值决定了
①get
方法的返回值类型
②set
方法中newValue
的类型 -
subscript
可以接受多个参数,并且类型任意
下标细节
-
subscript
可以没有set
方法,但必须要有get
方法
class Point {
var x = 0.0, y = 0.0
subscript(index: Int) -> Double {
get {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
}
如果只有get
方法,可以省略get
class Point {
var x = 0.0, y = 0.0
subscript(index: Int) -> Double {
if index == 0 {
return x
} else if index == 1 {
return y
}
return 0
}
}
- 下标可以设置参数标签
class Point {
var x = 0.0, y = 0.0
subscript(index i: Int) -> Double {
if i == 0 {
return x
} else if i == 1 {
return y
}
return 0
}
}
var p = Point()
p[index: 0]
- 下标可以是类型方法
class Sum {
static subscript(v1: Int, v2: Int) -> Int {
return v1 + v2
}
}
print(Sum[10,20]) // 30
结构体、类作为返回值对比
首先来看结构体
作为返回值
struct Point {
var x = 0, y = 0
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
get {point}
}
}
这里注意由于我们在这里没有用到索引,所以下标传入什么都没有影响:
var pm = PointManager()
print("subscript-------0")
print("x: \(pm[0].x)")
print("y: \(pm[0].y)")
print("subscript-------1")
print("x: \(pm[1].x)")
print("y: \(pm[1].y)")
print("subscript-------2")
print("x: \(pm[2].x)")
print("y: \(pm[2].y)")
/*输出结果*/
subscript-------0
x: 10
y: 20
subscript-------1
x: 10
y: 20
subscript-------2
x: 10
y: 20
- 大家注意到,上面的代码中,我们并没有实现
set
方法,那么在返回值是结构体
情况下,我们能不能修改,结构体里面的属性呢?
- 通过上图可知:很显然,返回值是
结构体
的情况并且没有实现set
方法的情况下,是不允许修改结构体
内部的属性
的。 - 因此我们来实现一下这种状况下的
set
方法:
struct Point {
var x = 10, y = 20
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
set {point = newValue}
get {point}
}
}
var pm = PointManager()
pm[0].x = 30
其实,pm[0].x = 30
等价于pm[0] = Point.init(x: 30, y: pm[0].y)
我们再来看一下 类
返回值会怎样
class Point {
var x = 10, y = 20
}
class PointManager {
var point = Point()
subscript(index: Int) -> Point {
get {point}
}
}
var pm = PointManager()
pm[0].x = 30
类作为返回值的话,再没有
set
方法的情况下,依然可以修改类
的相关属性其实,结构体、类作为返回值的这点区别,跟他们的
类型
是有关系的。
①结构体
是值类型,执行get
方法的时候会进行内存拷贝,返回到外面的pm[0]
是一个临时的Point
,所以外面的Point
是无法修改里面的Point
的内容的。
②类
是引用类型,此时的point
(注意大小写)就是一个指针变量,所以pm[0]
和point
指向的内存地址是同一块区域,所以是可以修改的。
对于值类型和引用类型有疑问的同学可以参考这篇文章:Swift进阶(四)--- 值类型 & 引用类型
接收多个参数的下标
class List {
var subList = [[0,1,2],
[4,5,6],
[7,8,9]]
subscript(section: Int, row: Int) -> Int {
set {
guard section >= 0 && section < 3 && row >= 0 && row < 3 else {
return
}
subList[section][row] = newValue
}
get {
guard section >= 0 && section < 3 && row >= 0 && row < 3 else {
return 0
}
return subList[section][row]
}
}
}
var list = List()
list[0, 1] = 100
list[2, 2] = 99
list[1, 1] = 88
print(list.subList)
/*输出结果*/
[[0, 100, 2], [4, 88, 6], [7, 8, 99]]