简体   繁体   English

为什么不在函数外部进行引用会创建保留周期?

[英]Why doesn't referencing outside of a function create retain cycle?

Sorry, but I know this is a really dumb question, and I already kind of 'know' the answer, but I need someone to clearly explain to me WHY the answer is what it is. 抱歉,但是我知道这是一个非常愚蠢的问题,我已经有点“知道”答案了,但是我需要有人清楚地向我解释为什么答案是它的意思。

Lately, I've become a bit obsessed/paranoid about retain cycles and memory leaks in my code, after going through some nightmarish debugging with various memory issues, so in the future I want to nip them in the bud. 最近,在经历了各种内存问题的噩梦调试之后,我对代码的保留周期和内存泄漏有些迷恋/偏执,所以将来我希望将它们扼杀在萌芽状态。 But after reading and learning a lot about ARC and retain cycles in Swift, although it makes sense, I still don't really have enough of an "intuitive" or natural feel for it, to feel confident that I could spot one, or the lack of one, as I'm coding. 但是,在阅读和学习了很多有关ARC的知识并保留了Swift的周期之后,尽管这很有意义,但我仍然没有足够的“直觉”或自然的感觉,以至于我有信心找到一个或一个我正在编码中缺少一个。 So I'm starting to become a little paranoid that I'm creating retain cycles with even basic stuff without realizing it. 因此,我开始变得有点偏执,因为我甚至没有意识到就创建了包含基本内容的保留周期。

So, with that in mind, why doesn't any ordinary function that uses a variable declared outside of it create a retain cycle? 因此,考虑到这一点,为什么任何使用在其外部声明的变量的普通函数都不会创建保留周期? For example: 例如:

    class someClass {
        let a = "I'm letter a"
        let moreLetters = addLetters()
        func addLetters () -> String { 
            let newString = a + "bcdefg"
            return newString
        }
    }

In this case, self.moreLetters references the function addLetters, and then the constant self.a is references from within the function addLetters. 在这种情况下,self.moreLetters引用函数addLetters,然后常量self.a是函数addLetters中的引用。 So would this create a retain cycle if I don't capture weak/unowned self? 如果我不捕捉弱者/无主者,那么这会形成一个保留周期吗? It seems absurd to me that something this simple would cause a problem...or is it? 在我看来,这种简单的事情会引起问题是荒谬的……还是吗? What about in a nested function, like this: 像这样的嵌套函数呢?

    func someFunction () -> String {
        let a = "I'm letter a"
        func addLetters () -> String { 
            let newString = a + "bcdefg"
            return newString
        }
        let moreLetters = addLetters()
        return moreLetters
    }

Would that also create a retain cycle? 这还会造成保留周期吗? (Yeah I know this is a convoluted way of performing a simple task; I'm just using this code as an example to make my point). (是的,我知道这是执行简单任务的复杂方法;我只是以这段代码为例来说明我的观点)。

Have I become super-paranoid and am severely overthinking things? 我是否变得超级偏执狂,并且对事情认真思考?

First, you need to understand how a basic retain cycle is formed. 首先,您需要了解如何形成基本的保留周期。 A retain cycle is formed when an object A refers to an object B strongly and at the same time. 当对象A同时强烈引用对象B时,会形成一个保留周期。 object B refers to object A strongly as well. 对象B也强烈指对象A。

Let's look at your first bit of code. 让我们看看您的第一段代码。

class someClass {
    let a = "I'm letter a"
    let moreLetters = addLetters()
    func addLetters () -> String { 
        let newString = a + "bcdefg"
        return newString
    }
}

Actually, a class by itself can never create retain cycles, so let's add some code to create an object: 实际上,类本身永远不会创建保留周期,因此让我们添加一些代码来创建对象:

var obj = someClass()

First, a is initialized to "I'm letter a". 首先,将a初始化为“我是字母a”。 After that, moreLetters is initialized by calling the method addLetters . 在此之后, moreLetters通过调用该方法初始化addLetters After the method returns, moreLetters is initialized to "I'm letter abcdefg". 方法返回后, moreLetters初始化为“ I'm letter abcdefg”。 So far so good. 到现在为止还挺好。

Now we set obj to nil : 现在我们将obj设置为nil

obj = nil

If a retain cycle were formed, obj would not be deinitialized. 如果形成了保留循环,则不会取消初始化obj However, in actuality, obj is deinitialized because nothing holds a strong reference to obj ! 但是,实际上, obj被取消了初始化,因为没有什么东西可以强烈引用obj

"Wait a minute!" “等一下!” you say, "But the method addLetters still refers to someClass because it has a in it!" 您会说:“但是方法addLetters仍然引用someClass因为其中包含a !” Well, in fact, addLetters has already returned! 好吧,事实上, addLetters已经回来了! Therefore, everything in it doesn't matter anymore! 因此,其中的所有内容都不再重要! In addition, addLetters belongs to obj , which you have already set to nil ! 另外, addLetters属于obj ,您已经将其设置为nil

Now let's look at your second code: 现在,让我们看一下您的第二个代码:

func someFunction () -> String {
    let a = "I'm letter a"
    func addLetters () -> String { 
        let newString = a + "bcdefg"
        return newString
    }
    let moreLetters = addLetters()
    return moreLetters
}

A retain cycle does not form because there isn't a even a reference type! 保留循环不会形成,因为甚至没有引用类型! There is no objects to be created. 没有要创建的对象。 All you did in the second code is playing with strings, which are value types. 您在第二个代码中所做的全部工作就是使用字符串(它们是值类型)。 Even if there were a class, a retain cycle would not form because as I said, when you set obj to nil , all the methods in it "disappear" because methods belong to objects. 即使有一个类,也不会形成保留周期,因为正如我所说,当将obj设置为nil ,其中的所有方法都会“消失”,因为方法属于对象。


What about those closures where I must write [weak self] or a retain cycle forms? 那些必须写[weak self]或保留周期表格的闭包呢?

Those closures are escaping closures . 这些闭包正在逃避闭包 Normal closures are deinitialized after they return. 普通闭包在返回后会被取消初始化。 However, escaping closures are retained by some object so they are not deinitialized immediately. 但是,转义的闭包由某些对象保留,因此它们不会立即取消初始化。 For more info, see Escaping Closures in Swift 有关更多信息,请参见在Swift中转义闭包

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM