4. Swift 更多关键字.png

mutating / nonmutating

mutating nonmutating 控制在方法中是否可以修改实例或其属性

  1. struct MyStruct {
  2. var property: String = ""
  3. /**
  4. 在结构体的方法中,属性默认不可变,即 nonmutating
  5. 若允许修改属性,需使用 mutating 修饰
  6. */
  7. mutating func test() {
  8. property = ""
  9. }
  10. /**
  11. 在结构体的计算属性的 set 方法中,属性默认可变,即 mutating
  12. 若不允许修改属性,需使用 nonmutating 修饰
  13. eg. var property2: String { nonmutating set get }
  14. */
  15. var property2: String {
  16. nonmutating set {
  17. // property = newValue
  18. }
  19. get {
  20. return ""
  21. }
  22. }
  23. }

class / static

class 修饰的类方法能被子类重写,而 static 修饰的类方法不能被子类重写

  1. class MyClass {
  2. class func test1() {
  3. }
  4. static func test2() {
  5. }
  6. }
  7. class MyClass2: MyClass {
  8. override class func test1() {
  9. }
  10. }

另外,class 修饰的类属性不能作为存储属性,只能作为计算属性。

self / Self / Type

self

self 表示当前实例
Type.self 用在类型后面取得类型本身
object.self 用在实例后面取得这个实例本身

  1. class MyClass {
  2. static func test() {}
  3. func test() {}
  4. }
  5. var object = MyClass()
  6. print(MyClass.self) // MyClass
  7. print(type(of: object) == MyClass.self) // true
  8. MyClass.self.init() // -> MyClass.init()
  9. MyClass.self.test() // -> MyClass.test()
  10. MyClass.self() // -> MyClass()
  11. MyClass.self().test() // -> MyClass().test()
  12. print(object) // swift_demo.MyClass
  13. print(object.self) // swift_demo.MyClass
  1. class MusicViewController {}
  2. class AbumViewController {}
  3. let controllerTypes: [AnyClass] = [MusicViewController.self, AbumViewController.self]

Self

Self 不仅指代的是实现该协议的类型本身,也包括了这个类型的子类

  1. Self 可以用于协议中限制相关的类型
  2. Self 可以用于类中来充当方法的返回值类型
  1. protocol Copyable {
  2. func copy() -> Self
  3. }
  4. class OneClass: Copyable {
  5. var number = 1
  6. func copy() -> Self {
  7. let obj = OneClass()
  8. obj.number = self.number
  9. return obj as! Self
  10. }
  11. }
  12. class TwoClass: Copyable {
  13. var number = 1
  14. required init() {}
  15. func copy() -> Self {
  16. let obj = type(of: self).init() // 若使用该方式初始化,则必须实现 required init() {}
  17. obj.number = self.number
  18. return obj
  19. }
  20. }
  21. var obj1 = OneClass()
  22. obj1.number = 10
  23. var obj2 = obj1.copy()
  24. print(obj2) // swift_demo.MyClass
  25. print(obj2.number) // 10

Type

X.self 属于 X.Type 类型

  1. class Person {
  2. func test1() -> Person.Type {
  3. return Person.self
  4. }
  5. func test2() -> Self {
  6. return self
  7. }
  8. }
  9. var personType: Person.Type = Person.self
  10. print(personType) // Person
  11. print(Person.self) // Person

[备注]:Swift 中 Self 与 self

indirect

递归枚举是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上 indirect 来表示该成员可递归,而且被 indirect 修饰符标记的枚举用例必须有一个关联值。

  1. enum ArithmeticExpression {
  2. case number(Int)
  3. indirect case addition(ArithmeticExpression, ArithmeticExpression)
  4. indirect case multiplication(ArithmeticExpression, ArithmeticExpression)
  5. }

也可以在枚举类型开头加上 indirect 关键字来表明它的所有成员都是可递归的

  1. indirect enum ArithmeticExpression {
  2. case number(Int)
  3. case addition(ArithmeticExpression, ArithmeticExpression)
  4. case multiplication(ArithmeticExpression, ArithmeticExpression)
  5. }

上面定义的枚举类型可以存储三种算术表达式:纯数字、两个表达式相加、两个表达式相乘。枚举成员 addition 和 multiplication 的关联值也是算术表达式。

下面的代码展示了使用 ArithmeticExpression 这个递归枚举创建表达式 (5 + 4) * 2 :

  1. let five = ArithmeticExpression.number(5)
  2. let four = ArithmeticExpression.number(4)
  3. let sum = ArithmeticExpression.addition(five, four)
  4. let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))

使用这个枚举:

  1. func evaluate(_ expression: ArithmeticExpression) -> Int {
  2. switch expression {
  3. case let .number(value):
  4. return value
  5. case let .addition(lhs, rhs):
  6. return evaluate(lhs) + evaluate(rhs)
  7. case let .multiplication(lhs, rhs):
  8. return evaluate(lhs) * evaluate(rhs)
  9. }
  10. }
  11. print(evaluate(product)) // 18

unowned

在 Swift 中,声明 unowned 相当于 unowned(safe)。当访问 unowned(safe) 类型的无主引用时,运行时会进行安全检查,如果对象已被销毁,将抛出异常并终止程序。

而 Swift 还提供了另一种不安全的无主引用 unowned(unsafe) 。它的作用效果实际上相当于 Objective-C 属性标示符中的 assign / unsafe_unretained。

访问 unowned(unsafe) 类型的无主引用时,运行时的安全检查被禁用,这时会有三种情况:

  • 废弃对象内存还未被覆盖:程序正常运行
  • 废弃对象内存被部分覆盖:奇怪的 crash,不确定的结果
  • 废弃对象内存正好填入新的对象:由于向新的对象发送了调用旧对象方法的消息,会出现 unrecognized selector exceptions

typealias

typealias 可以为某种类型自定义别名,例如:

  1. typealias Point = (Double, Double)
  2. let origin: Point = (0, 0)

typealias 还可以将多个协议组合成一个新类型,
协议组合列表中的每项元素必须是类名、协议名、协议组合名,且最多包含一个类。(Swift 只允许单继承)

  1. // 定义两个协议
  2. protocol Protocol1 {
  3. func methodForProtocol1()
  4. }
  5. protocol Protocol2 {
  6. func methodForProtocol2()
  7. }
  8. // 通常的协议组合方式
  9. protocol Protocol3: Protocol1, Protocol2 {}
  10. class Class1: Protocol3 {
  11. func methodForProtocol1() {}
  12. func methodForProtocol2() {}
  13. }
  14. // 使用 typealias 对协议组合,实例 1
  15. typealias Protocol1_Protocol2 = Protocol1 & Protocol2
  16. class Class2: Protocol1_Protocol2 {
  17. func methodForProtocol1() {}
  18. func methodForProtocol2() {}
  19. }
  20. // 使用 typealias 对协议组合,实例 2
  21. class SuperClass {
  22. func test() {}
  23. }
  24. typealias SuperClassAndProtocol1_Protocol2 = SuperClass & Protocol1_Protocol2
  25. class SubClass: SuperClassAndProtocol1_Protocol2 {
  26. func methodForProtocol1() {}
  27. func methodForProtocol2() {}
  28. override func test() {}
  29. }

required

必要构造器标识符, 修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 required 关键字修饰该构造器。

  1. class SuperClass {
  2. required init(value: String){}
  3. }

在子类重写父类的必要构造器时,必须在子类的构造器前也添加 required 关键字,不需要添加 override 关键字。

  1. class SubClass: SuperClass {
  2. required init(value: String) {
  3. super.init(value: value)
  4. }
  5. }

如果在有必要构造器的情况下,又去新增一个构造器,是不推荐的:

  1. class SubClass: SuperClass {
  2. init() {
  3. super.init(value: "")
  4. }
  5. required init(value: String) {
  6. fatalError("init(value:) has not been implemented")
  7. }
  8. }

如果子类重写了父类的指定构造器(override),并且该构造器满足了某个协议的要求(required),那么该构造器的实现需要同时标注 required 和 override 修饰符:

  1. protocol MyProtocol {
  2. init()
  3. }
  4. class SuperClass {
  5. init() {}
  6. }
  7. class SubClass: SuperClass, MyProtocol {
  8. required override init() {
  9. }
  10. }

**