Swift笔记 - 12.访问控制、初始化器、扩展、weak、unowned、AutoreleasePool

访问控制

  • 在访问权限控制这块,Swift提供了5个不同的访问级别(以下是从高到低排列,实体指被访问级别修饰的内容)
    • open:允许在定义实体的模块、其他模块中访问,允许其他模块进行继承、重写(open只能用在类、类成员上)
    • public:允许在定义实体的模块、其他模块中访问,不允许其他模块进行继承、重写
    • Dinternal:只允许在定义实体的模块中访问,不允许在其他模块中访问
    • fileprivate:只允许在定义实体的源文件中访问
    • private:只允许在定义实体的封闭声明中访问
  • 绝大部分实体默认都是internal级别

访问控制级别的使用准则

  • 一个实体不可以被更低访问级别的实体定义,比如

    • 变量\常量类型 变量\常量
    • 参数类型、返回值类型 函数
    • 父类 子类
    • 父协议 子协议
    • 原类型 typealias
    • 原始值类型、关联值类型 枚举类型
    • 定义类型A时用到的其他类型 类型A
  • 炎型的访问级别会影哈成员(属性、方法、初始化器、下标),嵌套炎型的默认访问圾别

    • 一般情况下,类型为privatefileprivate那么成员 privatefileprivate
    • 一般情況下,类型为internalpublic,那么成员\嵌套类型默认是internal
public class PublicClass {
    public var p1 = 8 // public
    var p2 = 8 // internal
    fileprivate func f1() {} // fileprivate
    private func f2() {} // private
}

class InnerClass { // internal
    var p = 0 // internal
    fileprivate func f1() {} //fileprivate
    private func f2() {} //private
}

fileprivate class PilePrivateClass ( // fileprivate
    func 110) 0) / fileprivate
    private func 12() { // private
}
private class PrivateClass { // private
    func f() {} // private
}
  • 子类重写的成员访问级别必须 父炎的成员访向级别

  • gettersetter默认自动接收它们所属环境的访问级别

    • 可以给setter单独设置一个比getter更低的访问坡别,用以限制写的权限
fileprivate(set) public var nun = 10
class Person {
    private(set) var age = 0
    fileprivate(set) public var weight: Int
    set {}
    get { 10 }
    internal(set) public subscript(index: Int) -> Int (
    set {}
    get { index }
}

初始化器

  • 如果一个public类想在另一个横块调用编泽生成的默认无参初始化器,必须显式提供pubLic的无參初始化器

    • 因为public类的默认初始化器是internal级别
  • required初始化器必须跟它所履类拥有相同的访问级别

  • 如果结构体有private\fileprivate的存储实例属性,那么它的成员初始化器也是private fileprivate

    • 否则默认就是internal

扩展(Extension)

  • Swift中的扩展,有点类似于OC中的分类(Category)

    • 扩展可以为枚举、结构体、类、协议添加新功能
    • 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等等
  • 扩展不能办到的事情

    • 不能覆盖原有的功能
    • 不能添加存储属性,不能向已有的属性添加属性观察器
    • 不能添加父类
    • 不能添加指定初始化器,不能添加反初始化器

Extension的计算属性、下标、方法、嵌套类型

extension Double {
    var km: Double { self * 1 000.0 }
    var m: Double { self }
    var dm: Double $ self / 100.0
    var cm: Double { self / 10.0 }
    var mm: Double { self / 1 000.0 }
}

extension Array {
    subscript(nullable idx: Int) -> Element? {
        if (startIndex..<endIndex).contains(idx) {
            return self[idx]
        }
        return nil
    }
}

extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self { task() }
    }
    mutating func square() -> Int {
        self = self * self
        return self
    }
    enum Kind { case negative, zero, positive }
    var kind: Kind {
        switch self {
            case 0: return .zero
            case let x where x > 0: return .positive
            default: return .negative
        }
    }
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex { decimalBase *= 10 }
        return (self / decimalBase) % 10
    }
}

协议、初始化器

class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
extension Person : Equatable {
    static func == (left: Person, right: Person) -> Bool {
        left.age == right.age && left.name == right.name
    }
    convenience init() {
        self.init(age: 0, name: "'")
    }
}

struct Point {
    var x: Int = 0
    var y: Int = 0
}
extension Point {
    init(_ point: Point) {
        self.init(x: point.x, y: point.y)
    }
}
var p1 = Point()
var p2 = Point(x: 10)
var p3 = Point(y: 20)
var p4 = Point(x: 10, y: 20)
var p5 = Point(p4)
  • 如果希望自定义初始化器的同时,编译器也能够生成默认初始化器
  • 可以在扩展中编写自定义初始化器
  • 类遵守协议实现的required初始化器,不能写在扩展中

使用扩展来遵守协议,也可以使用扩展来为协议添加方法实现

  • 如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议
    • 可以通过扩展来让它遵守这个协议
protocol TestProtocol {
    func test()
}
class TestClass {
    func test() {
        print("test")
    }
}
extension TestClass : TestProtocol {}
  • 编写一个西数,判断一个整数是否为奇数?
func isOdd<T: BinaryInteger>(_ i: T) -> Bool {
    1 % 2 != 0
}
  • 扩展可以给协议提供默认实现,也间接实现『可选协议』的效果
  • 扩展可以给协议扩态『协议中从末声明过的方法』
protocol TestProtocol {
    func test1()
}
extension TestProtocol {
    func test1() {
        print ("TestProtocol test1")
    }
    func test2() {
        print ("TestProtocol test2")
    }
}

class TestClass : TestProtocol {}
var cls = TestClass()
cls.test1() // TestProtocol test1
cls.test2() // TestProtocol test2
var cls2: TestProtocol = TestClass()
cls2.test1() // TestProtocol test1
cls2.test2() // TestProtocol test2
class TestClass : TestProtocol {}
func test1() { print ("TestClass test1") }
func test2() { print ("TestClass test2") }
var cls = TestClass()
cls.test1() // TestClass test1
cls.test2() // TestClass test2
var cls2: TestProtocol = TestClass()
cls2.test1() // TestClass test1
cls2.test2() // TestProtocol test2
extension BinaryInteger {
    func isOdd() -> Bool { self % 2 != 0 }
}
var age: Int8 = 10

print(age.isOdd())
print(10.is0dd())
print((-3).isodd())

弱引用

  • 跟OC一样,Swift也是采取基于引用计数的ARC内存管理方案(针对堆空间)

  • Swift的ARC中有3种引用

    • 强引用(strong reference):默认情况下,引用都是强引用
  • 弱引用(weak reference):通过weak定义弱引用

    • 必须是可选类型的var,因为实例销毁后,ARC会自动将弱引用设置为nil
    • ARC自动给弱引用设置nil时,不会触发属性观察器
  • 无主引用(unowned reference):通过unowned定义无主引用

    • 不会产生强引用,实例销段后仍然存储着实例的内存地址(类似于OC中的unsafe_unretained)
    • 试图在实例销毁后访问无主引用,会产生运行时错误(野指针)
    • •Fatal error: Attempted to read an unowned reference but object 0x0 was already deallocated

weak、unowned的使用限制

  • weakunowned只能用在类实例上面
protocol Livable : AnyObject {}
class Person {}

weak var pO: Person?
weak var p1: AnyObject?
weak var p2: Livable?

unowned var p10: Person?
unowned var p11: AnyObject?
unowned var p12: Livable?

AutoreleasePool

public func autoreleasepool<Result>(invoking body: () throws -> Result) rethrows -> Result
autoreleasepool {
    let p = MJPerson(age: 20, name: "Jack")
    p.run()
}

继续阅读