首页 文章

如何使用自动参考计数(ARC)?

提问于
浏览
2

在Swift中,我们主要使用许多类,如,

  • UITableView

  • UIStepper

  • UILabel

  • NSTimer

  • UISlider等 .

一个例子:

var slider:UISlider!

我的问题是我们是否必须将所有这些创建为 prefixing 并将其作为 weak ,以便ARC不会对其进行强有力的保持,因此 ARC 可以在需要时删除它,或者仅创建 strong reference 并将其设置为 nil viewDidUnload deligate ??

例如:

slider = nil

到了我实际 don't 知道如何 manually use ARC 或手动处理ARC根本不需要?我不知道这种食物的处理方式

如果您遇到过这个并找到解决方案,请分享一下......

提前致谢....

3 回答

  • 0

    ARC( Automatic Reference Counting) 在Swift中很好地解释了official documentation .

    您可以在下面找到ARC的4个重要方面的简单回顾 .

    1.基础知识

    ARC关联到类a retainCount 整数的每个实例 . 此值表示对该特定实例的强引用数 . 当此数字变为0时,将释放实例使用的内存 .

    class Something {}
    var aVariable = Something()
    // now the reference counting for this particular instance of Something is 1
    

    现在我们的 Something 实例保留在内存中,因为它的 retainCount 值是 1 .

    var anotherVariable = aVariable
    

    现在我们对 Something 的实例有强烈的引用 . 好!它 retainCount 现在是 2 ,实例仍保留在内存中!

    aVariable = nil
    

    retainCount 刚刚成为 1 . 没问题,实例仍在内存中 .

    anotherVariable = nil
    

    最后,我们实例的 retainCount 已成为 0 . 这意味着该实例已被释放,无法再访问 .

    2.在完成变量后,你应该设置为nil吗?

    Nope. 事实上,当变量超出范围时,ARC会自动减少所引用实例的 retainCount .

    在以下示例中,在最后 } 之前 Something 实例的 retainCount 减小并达到值 0 (并被释放) .

    func doSomethingUseful() {
        let something = Something()
        // ... do very important stuff here
    }
    

    因此,在常见的情况下,您不需要将变量设置为 nil ,以强制ARC释放引用的实例 .

    另一个例子:

    class Son {}
    
    class Father {
        var sons: [Son]
        init (sons: [Son]) {
            self.sons = sons
        }
    }
    
    func lifeGoesOn() {
        let son = Son()
        // here the referenceCout of the instance of Son is 1
        let father = Father(sons: [son])
        // here the referenceCount of the instance of Son is 2...
    
        // now variable son goes out of scope so the reatinCount of the instance of Son becomes 1
        // also father goes out of scope, so the variable father.sons goes out of scope as well, so the `retainCount` of the instance of Son becomes 0
        // and so both the instances of Father and Son gets freed
    }
    

    你可以看到这就像多米诺骨牌效应 . 释放实例时,将删除对其他实例的所有引用 . 所以引用的实例的 retainCounts 减少了 . 如果成为 0 ,他们就会被释放 . 等等...

    3.保留周期

    好的,如果我有2个课程,会发生什么?

    class Son {
        let father:Father
        init(father:Father) {
            self.father = father
        }
    }
    
    class Father {
        var sons: [Son]
        init (sons: [Son]) {
            self.sons = sons
        }
    }
    

    让我们现在创建一个从 fatherson 的引用,反之亦然从 son 到它的 father .

    func lifeGoesOn() {
        var father = Father(sons:[])
        // retainCount of the instance of Father is 1
        var son = Son(father: father)
        // retainCount of the instance of Father is 2
        // retainCount of the instance of Son is 1
        father.sons.append(son)
        // retainCount of the instance of Father is 2
        // retainCount of the instance of Son is 2
    
        // Now we have a problem
    }
    

    在函数中,父变量超出范围,因此 Father 实例的 retainCount 变为 1 . 类似地,变量 son 超出范围, Son 实例的 retainCount 变为 1 .

    这里的问题是 Son 的实例引用了 Father 的实例(将此实例保留在活动内存中) . 并且 Father 的实例引用了 Son 的实例 . 这两个实例不应再存在于内存中 . 程序员无法访问它们,因为引用它们的所有变量都消失了 .

    这是个问题 .

    4.弱引用

    构建代码时,应注意强保留周期 . 让我们如何重构我们的代码来解决这个问题 .

    class Son {
        weak var father:Father?
        init(father:Father) {
            self.father = father
        }
    }
    

    现在从 SonFather 的引用是 weak . 这意味着当ARC计算实例的(强)引用数时,它不计算在内 . 这解决了上一段中看到的问题 .

    我希望现在的主题更加清晰 . 我没有涉及几种情况 . 同样,官方文档非常好,详尽无遗 .

    更新(更好地回答下面的评论)

    如果你有一个自定义 UIViewController (让我们称之为 MyCustomViewController )并且这个类具有对象的强大属性,让我们看看会发生什么 .

    class MyCustomViewController : UIViewController {
        var something = Something()
    }
    
    class Something {
        init() { // called when memory is allocated
            debugPrintln("The instance of Something has been created")
        }
        deinit { // called when memory is freed
            debugPrintln("The instance of Something has been freed")
        }
    }
    

    当您呈现 MyCustomViewController 时,会创建 MyCustomViewController 的实例 . 然后还会创建 Something 的实例 .

    现在 MyCustomViewController 的实例被 UINavigationController 引用,所以 retaintCount = 1 . 类似地, Something 的实例由 MyCustomViewController 的实例引用,因此它具有 retainCount = 1 .

    所以 UINavigationController keeps alive 的实例 MyCustomViewController 的实例 . 而 MyCustomViewController keeps alive 的实例 Something .

    UINavigationController - (强) - > MyCustomViewController - (强) - >东西

    接下来您决定关闭 MyCustomViewController ,因此iOS会将其设置为动画以离开屏幕 . 当它不再可见时,它将从 UINavigationController 实例的引用中移除到实例 MyCustomViewController .

    UINavigationController - (REMOVED) - MyCustomViewController - (强) - >东西

    这意味着 MyCustomViewController 实例的 retainCount 变为0,因为:现在没有人引用它!

    所以 MyCustomViewController 的实例将从内存中删除 . 在这个过程中,它的属性是无效的 .

    UINavigationController - (REMOVED) - [自由记忆] - (删除) - 东西

    现在 Something 实例的 retainCount 已经变为0.所以它也将从内存中删除 .

    UINavigationController - (REMOVED) - [可用内存] - (删除) - > [可用内存]

    最后,我覆盖了 Somethinginitdeinit 方法,以便您可以跟踪相关实例的分配和释放 . 查看日志(或使用断点),您可以验证我在这里说的内容 .

    希望这可以帮助 .

  • 0

    如果您正在讨论由视图本身初始化的视图控制器属性(例如 UILabel 或您在IB中定义的 UIView 的几乎任何子类),Xcode将自动将它们分配为 weak 作为视图(而不是视图控制器) )创造了强有力的参考 .

    大多数情况下,您不需要手动将 weak 添加到您的属性中,除非您在代码中的其他位置定义了强关系(这是您拥有委托时的典型情况) .

  • 2

    ARC大多只是起作用 . 在使用Cocoa类(例如您列出的类)时,通常不必担心声明弱 .

    当你有自己开发的具有双向引用的不同类时,你只需要考虑它 . (Apple's example中的公寓类和人员类) .

相关问题