【问题标题】:ARC(Automatic Reference Counting) in ActionARC(自动引用计数)在行动
【发布时间】:2015-05-26 11:32:26
【问题描述】:

我目前正在关注Apple Documentation。这是我的问题:

class Person {
    let name: String
    init(name: String) {
        self.name = name
        println("\(name) is being initialized")
    }
    deinit {
        println("\(name) is being deinitialized")
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        var reference1: Person?
        var reference2: Person?
        var reference3: Person?
        reference1 = Person(name: "John Appleseed")
        // prints "John Appleseed is being initialized
        reference2 = reference1
        reference3 = reference1

        reference1 = nil
        reference2 = nil
    }
}

reference1 等于nil 之后,ARC 释放实例并打印"John Appleseed is being deinitialized"

不应该在reference3 = nil之后解除分配吗?

【问题讨论】:

  • @JakubVano 要获取更多信息,我正在 viewDidLoad() 方法中运行此代码。但是 reference3 不是 nil,即使存在强引用,编译器也会释放实例。
  • 该屏幕截图添加了混乱,而不是清晰。
  • 您如何确定deinit 发生的确切时刻?我希望它在方法返回后立即被调用(绝对不是片刻之后)。由于某种优化,它可能会被提前调用,但在方法返回后它肯定不会闲逛。
  • 如果我错了,请纠正我,对 Person 实例有 3 个强引用。我通过将它们设置为 nil 来破坏 2 个引用。但是,仍然有 1 个强参考。编译器如何调用 deinit 方法?
  • 因为第三个一旦超出范围就设置为nil,也就是viewDidLoad方法返回时。

标签: swift automatic-ref-counting


【解决方案1】:

这里的问题是范围问题。我们可以通过断点了解更多信息。

在这里,我们在初始化 reference1 之前就停止了。
所有变量都应该是 nil

reference1初始化之后呢?


好的,让我们在设置reference2reference3 之后向前跳:

所有三个变量都指向同一个内存位置,我们可以看到初始化程序只运行了一次。这些都指向同一个位置。

让我们向前一步:

reference1 现在指向None。它是nildeinit 方法尚未被调用并打印其消息。

让我们更进一步:

现在reference1reference2 预计都是nil。我添加的println 语句被调用。但是deinit 没有运行并且reference3 不是nil

下一步是逐步退出该方法。一旦我们离开方法,变量就会超出范围,deinit 会被调用:

【讨论】:

    【解决方案2】:

    它正在解除分配,因为编译器能够识别不再使用本地创建的对象。例如在下面的代码中,viewDidLoad 方法执行后,Person 将被释放,因为将来没有人可以使用 person 对象。

    override func viewDidLoad() {
            super.viewDidLoad()
            // Do any additional setup after loading the view, typically from a nib.\
    
            var reference1: Person?
            var reference2: Person?
            var reference3: Person?
            reference1 = Person(name: "John Appleseed")
            // prints "John Appleseed is being initialized
            reference2 = reference1
            reference3 = reference1
    
            reference1 = nil
            reference2 = nil
    
    //        println(reference3?.name)
    }
    

    如果要保留对象,则需要将reference3 创建为property,如下所示:

    class ViewController: UIViewController {
    
        var reference3 : Person?
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            var reference1: Person?
            var reference2: Person?
    
            reference1 = Person(name: "John Appleseed")
            // prints "John Appleseed is being initialized
            reference2 = reference1
            reference3 = reference1
    
            reference1 = nil
            reference2 = nil
    
    //        println(reference3?.name)
        }
    
        override func viewDidAppear(animated: Bool) {
            super.viewDidAppear(animated)
            println(reference3?.name)
        }
    
    }
    

    【讨论】:

    • 即使 reference3 不是全局的,我也可以访问 reference3?.name
    • 如果您在 didLoad 中声明 reference3 并在 didAppear 中使用,则任何应用都不会编译。
    猜你喜欢
    • 2012-03-21
    • 2012-03-13
    • 1970-01-01
    • 2012-01-11
    • 1970-01-01
    • 2015-09-29
    • 2012-02-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多