
mutating / nonmutating
mutating nonmutating 控制在方法中是否可以修改实例或其属性
struct MyStruct {var property: String = ""/**在结构体的方法中,属性默认不可变,即 nonmutating若允许修改属性,需使用 mutating 修饰*/mutating func test() {property = ""}/**在结构体的计算属性的 set 方法中,属性默认可变,即 mutating若不允许修改属性,需使用 nonmutating 修饰eg. var property2: String { nonmutating set get }*/var property2: String {nonmutating set {// property = newValue}get {return ""}}}
class / static
class 修饰的类方法能被子类重写,而 static 修饰的类方法不能被子类重写
class MyClass {class func test1() {}static func test2() {}}class MyClass2: MyClass {override class func test1() {}}
另外,class 修饰的类属性不能作为存储属性,只能作为计算属性。
self / Self / Type
self
self 表示当前实例
Type.self 用在类型后面取得类型本身
object.self 用在实例后面取得这个实例本身
class MyClass {static func test() {}func test() {}}var object = MyClass()print(MyClass.self) // MyClassprint(type(of: object) == MyClass.self) // trueMyClass.self.init() // -> MyClass.init()MyClass.self.test() // -> MyClass.test()MyClass.self() // -> MyClass()MyClass.self().test() // -> MyClass().test()print(object) // swift_demo.MyClassprint(object.self) // swift_demo.MyClass
class MusicViewController {}class AbumViewController {}let controllerTypes: [AnyClass] = [MusicViewController.self, AbumViewController.self]
Self
Self 不仅指代的是实现该协议的类型本身,也包括了这个类型的子类
- Self 可以用于协议中限制相关的类型
- Self 可以用于类中来充当方法的返回值类型
protocol Copyable {func copy() -> Self}class OneClass: Copyable {var number = 1func copy() -> Self {let obj = OneClass()obj.number = self.numberreturn obj as! Self}}class TwoClass: Copyable {var number = 1required init() {}func copy() -> Self {let obj = type(of: self).init() // 若使用该方式初始化,则必须实现 required init() {}obj.number = self.numberreturn obj}}var obj1 = OneClass()obj1.number = 10var obj2 = obj1.copy()print(obj2) // swift_demo.MyClassprint(obj2.number) // 10
Type
X.self 属于 X.Type 类型
class Person {func test1() -> Person.Type {return Person.self}func test2() -> Self {return self}}var personType: Person.Type = Person.selfprint(personType) // Personprint(Person.self) // Person
[备注]:Swift 中 Self 与 self
indirect
递归枚举是一种枚举类型,它有一个或多个枚举成员使用该枚举类型的实例作为关联值。使用递归枚举时,编译器会插入一个间接层。你可以在枚举成员前加上 indirect 来表示该成员可递归,而且被 indirect 修饰符标记的枚举用例必须有一个关联值。
enum ArithmeticExpression {case number(Int)indirect case addition(ArithmeticExpression, ArithmeticExpression)indirect case multiplication(ArithmeticExpression, ArithmeticExpression)}
也可以在枚举类型开头加上 indirect 关键字来表明它的所有成员都是可递归的
indirect enum ArithmeticExpression {case number(Int)case addition(ArithmeticExpression, ArithmeticExpression)case multiplication(ArithmeticExpression, ArithmeticExpression)}
上面定义的枚举类型可以存储三种算术表达式:纯数字、两个表达式相加、两个表达式相乘。枚举成员 addition 和 multiplication 的关联值也是算术表达式。
下面的代码展示了使用 ArithmeticExpression 这个递归枚举创建表达式 (5 + 4) * 2 :
let five = ArithmeticExpression.number(5)let four = ArithmeticExpression.number(4)let sum = ArithmeticExpression.addition(five, four)let product = ArithmeticExpression.multiplication(sum, ArithmeticExpression.number(2))
使用这个枚举:
func evaluate(_ expression: ArithmeticExpression) -> Int {switch expression {case let .number(value):return valuecase let .addition(lhs, rhs):return evaluate(lhs) + evaluate(rhs)case let .multiplication(lhs, rhs):return evaluate(lhs) * evaluate(rhs)}}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 可以为某种类型自定义别名,例如:
typealias Point = (Double, Double)let origin: Point = (0, 0)
typealias 还可以将多个协议组合成一个新类型,
协议组合列表中的每项元素必须是类名、协议名、协议组合名,且最多包含一个类。(Swift 只允许单继承)
// 定义两个协议protocol Protocol1 {func methodForProtocol1()}protocol Protocol2 {func methodForProtocol2()}// 通常的协议组合方式protocol Protocol3: Protocol1, Protocol2 {}class Class1: Protocol3 {func methodForProtocol1() {}func methodForProtocol2() {}}// 使用 typealias 对协议组合,实例 1typealias Protocol1_Protocol2 = Protocol1 & Protocol2class Class2: Protocol1_Protocol2 {func methodForProtocol1() {}func methodForProtocol2() {}}// 使用 typealias 对协议组合,实例 2class SuperClass {func test() {}}typealias SuperClassAndProtocol1_Protocol2 = SuperClass & Protocol1_Protocol2class SubClass: SuperClassAndProtocol1_Protocol2 {func methodForProtocol1() {}func methodForProtocol2() {}override func test() {}}
required
必要构造器标识符, 修饰符用于修饰类的指定构造器或便利构造器,表示该类所有的子类都必须实现该构造器。在子类实现该构造器时,必须同样使用 required 关键字修饰该构造器。
class SuperClass {required init(value: String){}}
在子类重写父类的必要构造器时,必须在子类的构造器前也添加 required 关键字,不需要添加 override 关键字。
class SubClass: SuperClass {required init(value: String) {super.init(value: value)}}
如果在有必要构造器的情况下,又去新增一个构造器,是不推荐的:
class SubClass: SuperClass {init() {super.init(value: "")}required init(value: String) {fatalError("init(value:) has not been implemented")}}
如果子类重写了父类的指定构造器(override),并且该构造器满足了某个协议的要求(required),那么该构造器的实现需要同时标注 required 和 override 修饰符:
protocol MyProtocol {init()}class SuperClass {init() {}}class SubClass: SuperClass, MyProtocol {required override init() {}}
**
