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) // MyClass
print(type(of: object) == MyClass.self) // true
MyClass.self.init() // -> MyClass.init()
MyClass.self.test() // -> MyClass.test()
MyClass.self() // -> MyClass()
MyClass.self().test() // -> MyClass().test()
print(object) // swift_demo.MyClass
print(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 = 1
func copy() -> Self {
let obj = OneClass()
obj.number = self.number
return obj as! Self
}
}
class TwoClass: Copyable {
var number = 1
required init() {}
func copy() -> Self {
let obj = type(of: self).init() // 若使用该方式初始化,则必须实现 required init() {}
obj.number = self.number
return obj
}
}
var obj1 = OneClass()
obj1.number = 10
var obj2 = obj1.copy()
print(obj2) // swift_demo.MyClass
print(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.self
print(personType) // Person
print(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 value
case 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 对协议组合,实例 1
typealias Protocol1_Protocol2 = Protocol1 & Protocol2
class Class2: Protocol1_Protocol2 {
func methodForProtocol1() {}
func methodForProtocol2() {}
}
// 使用 typealias 对协议组合,实例 2
class SuperClass {
func test() {}
}
typealias SuperClassAndProtocol1_Protocol2 = SuperClass & Protocol1_Protocol2
class 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() {
}
}
**