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

时间:2017-01-01 08:08:22

标签: ios swift memory-leaks retain-cycle

很抱歉,但我知道这是一个非常愚蠢的问题,而且我已经“知道”了答案,但我需要有人向我清楚地解释为什么答案就是这样。

最近,我对代码中的保留周期和内存泄漏变得有点痴迷/偏执,经过一些关于各种内存问题的噩梦调试后,所以将来我想把它们扼杀在萌芽状态。但是在阅读并学习了很多关于ARC并且在Swift中保留循环之后,尽管它有意义,但我仍然没有足够的“直观”或自然的感觉,对我有信心可以发现它,或者缺乏一个,因为我正在编码。所以我开始变得有点偏执,我正在创建保留周期甚至基本的东西而没有意识到它。

因此,考虑到这一点,为什么使用在其外部声明的变量的任何普通函数都不会创建保留周期?例如:

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

在这种情况下,self.moreLetters引用函数addLetters,然后常量self.a是函数addLetters中的引用。如果我不捕捉弱/无主的自我,那么这会创建一个保留周期吗?对我来说,这么简单会导致问题......或者是这样的事情似乎很荒谬?在嵌套函数中,如下所示:

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

这会创建一个保留周期吗? (是的,我知道这是一种执行简单任务的复杂方式;我只是以此代码为例来表达我的观点)。

我是否变得超级偏执并严重过度思考?

1 个答案:

答案 0 :(得分:2)

首先,您需要了解基本保留周期是如何形成的。当对象A强烈且同时地引用对象B时,形成保留周期。对象B也强烈地引用对象A.

让我们看看你的第一段代码。

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

实际上,一个类本身永远不会创建保留周期,所以让我们添加一些代码来创建一个对象:

var obj = someClass()

首先,a初始化为"我是#a"。之后,通过调用方法moreLetters初始化addLetters。方法返回后,moreLetters被初始化为"我是字母abcdefg"。到目前为止一切都很好。

现在我们将obj设置为nil

obj = nil

如果形成保留周期,obj将不会被取消初始化。但是,实际上obj已取消初始化,因为没有任何内容可以强烈引用obj

"等一下!"你说,"但方法addLetters仍然引用someClass,因为它中有a!"嗯,事实上,addLetters已经回来了!因此,其中的一切都不重要了!此外,addLetters属于obj,您已将其设置为nil

现在让我们看看你的第二个代码:

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

由于没有参考类型,因此不会形成保留周期!没有要创建的对象。你在第二个代码中所做的只是使用字符串,这是值类型。即使有一个类,也不会形成一个保留周期,因为正如我所说,当你将obj设置为nil时,它中的所有方法都会消失"因为方法属于对象。

那些我必须写[weak self]或保留周期表格的闭包呢?

这些闭包是转义闭包。正常闭合在返回后被去初始化。但是,某些对象会保留转义闭包,因此不会立即取消初始化。有关详细信息,请参阅Escaping Closures in Swift