diff --git a/source/02_language_guide/24_Automatic_Reference_Counting.md b/source/02_language_guide/24_Automatic_Reference_Counting.md index fc8f47b4..84556581 100755 --- a/source/02_language_guide/24_Automatic_Reference_Counting.md +++ b/source/02_language_guide/24_Automatic_Reference_Counting.md @@ -242,7 +242,7 @@ unit4A = nil 和弱引用类似,*无主引用*不会牢牢保持住引用的实例。和弱引用不同的是,无主引用在其他实例有相同或者更长的生命周期时使用。你可以在声明属性或者变量时,在前面加上关键字 `unowned` 表示这是一个无主引用。 -无主引用通常都被期望拥有值。不过 ARC 无法在实例被销毁后将无主引用设为 `nil`,因为非可选类型的变量不允许被赋值为 `nil`。 +但和弱引用不同,无主引用通常都被期望拥有值。所以,将值标记为无主引用不会将它变为可选类型,ARC 也不会将无主引用的值设置为 `nil`。 > 重点 > @@ -321,6 +321,64 @@ john = nil > 上面的例子展示了如何使用安全的无主引用。对于需要禁用运行时的安全检查的情况(例如,出于性能方面的原因),Swift 还提供了不安全的无主引用。与所有不安全的操作一样,你需要负责检查代码以确保其安全性。 > 你可以通过 `unowned(unsafe)` 来声明不安全无主引用。如果你试图在实例被销毁后,访问该实例的不安全无主引用,你的程序会尝试访问该实例之前所在的内存地址,这是一个不安全的操作。 +### 无主可选引用 {#unowned-optional-references} + +可以将类的可选引用标记为无主引用。按照 ARC 的所有权模型,无主可选引用和弱应用都可以在同一上下文里使用。区别是使用无主可选引用时,需要保证引用的对象总是合法的,或者将它设置为 `nil`。 + +这里有一个追踪学校特定系科所提供课程的示例: + +```swift +class Department { + var name: String + var courses: [Course] + init(name: String) { + self.name = name + self.courses = [] + } +} + +class Course { + var name: String + unowned var department: Department + unowned var nextCourse: Course? + init(name: String, in department: Department) { + self.name = name + self.department = department + self.nextCourse = nil + } +} +``` + +`Department` 维持着系科对其提供的每个课程的强引用。在 ARC 的所有权模型中,系科持有它的课程。`Course` 持有两个无主引用,一个是它对应的系科,另一个是学生应该修的后续课程,但课程不应该持有这两个对象。每个课程都有对应的系科,所以 `department` 属性不是可选的。然而某些课程没有推荐的后续课程,所以 `nextCourse` 属性是可选的。 + +下面是使用这些类的示例: + +```swift +let department = Department(name: "Horticulture") + +let intro = Course(name: "Survey of Plants", in: department) +let intermediate = Course(name: "Growing Common Herbs", in: department) +let advanced = Course(name: "Caring for Tropical Plants", in: department) + +intro.nextCourse = intermediate +intermediate.nextCourse = advanced +department.courses = [intro, intermediate, advanced] +``` + +上面的代码创建系科和它的三个课程。intro 和 intermediate 课程都将建议的后续课程存储在它们的 `nextCourse` 属性中,通过无主可选引用关联学生完成该课程后的应修课程。 + +![](https://docs.swift.org/swift-book/_images/unownedOptionalReference_2x.png) + +无主可选引用不会保持对包装类实例的强持有,所以它不会影响 ARC 对该实例的析构。在 ARC 下,无主可选引用除了可以为 `nil` 外,其他表现和无主引用一致。 + +类似不可选无主引用,需要保证确保 `nextCourse` 总是引用一个还没被析构的课程。在这个案例中,假如需要从 `department.courses` 里删除一个课程,同时也需要在其他可能引用它的课程里移除它。 + +> 注意 +> +> 可选值的底层类型是 `Optional`,是 Swift 标准库里的枚举。然而,可选是值类型不能被标记为 `unowned` 的唯一例外。 +> +> 可选值包装的类不使用引用计数,所以不需要维持对可选值的强引用。 + ### 无主引用和隐式解包可选值属性 {#unowned-references-and-implicitly-unwrapped-optional-properties} 上面弱引用和无主引用的例子涵盖了两种常用的需要打破循环强引用的场景。 diff --git a/source/03_language_reference/03_Types.md b/source/03_language_reference/03_Types.md index 609e34de..06234898 100644 --- a/source/03_language_reference/03_Types.md +++ b/source/03_language_reference/03_Types.md @@ -444,6 +444,38 @@ let anotherInstance = metatype.init(string: "some string") #### metatype-type {#metatype-type} > *元类型* → [类型](#type) **.** **Type** | [类型](#type) **.** **Protocol** +## 任意类型{#any-type-h} + +`Any` 类型可以包含其他类型的值。`Any` 可以用于以下类型实例的具体类型: + +* 类、结构体或枚举 +* 元类型,例如 `Int.self` +* 任意类型组成的元组 +* 闭包或函数类型 + +```Swift +let mixed: [Any] = ["one", 2, true, (4, 5.3), { () -> Int in return 6 }] +``` + +当使用 `Any` 作为实例的具体类型时,访问其属性和方法之前需要转换其为已知类型。类型是 `Any` 的实例保留其原始的动态类型,并且可以通过任一类型转换操作符 `as`、`as?` 或 `as!` 进行类型转换。例如下文,使用 `as?` 将进行混合数组中第一个对象根据情况向下转换为 `String` 。 + +```swift +if let first = mixed.first as? String { + print("The first item, '\(first)', is a string.") +} +// 打印 "The first item, 'one', is a string." +``` + +关于转换的更多细节,请参阅 [类型转换](../02_language_guide/18_Type_Casting.md)。 + +`AnyObject` 协议和 `Any` 类型类似。所有类隐式遵循 `AnyObject`。和 `Any` 不一样,`AnyObject` 定义在 Swift 标准库中而不是在语言里。更多细节,请参阅 [类专属的协议](../02_language_guide/121_Protocols.md#class-only-protoco) 和 [`AnyObject`](https://developer.apple.com/documentation/swift/anyobject)。 + +> 任意类型语法 + +#### any-type{#any-type} + +> *任意类型* → **Any** + ## 自身类型 {#self-type-h} `Self` 类型不是具体的类型,而是让你更方便的引用当前类型,不需要重复或者知道该类的名字。