Swift nested function circular reference

1,120 阅读1分钟

在 Swift Closure 中调用 Nested function,会造成 circle retain 吗?

写了一个 demo:

import UIKit

class A {
    let b: B?
    
    init(b: B?) {
        self.b = b
    }
    
    deinit {
        print("deinit a")
    }
    
    func test() {
        func __nestedFunction() {
            print("nested function")
        }
        b?.block = {
            __nestedFunction()
        }
    }
    
    func test2() {
        print("test 2")
    }
}

class B {
    var block: (() -> Void)?
    deinit {
        print("deinit b")
    }
    
    func excuteBlock() {
        block?()
    }
}

var b: B? = B()
var a: A? = A(b: b)
a?.test()
b?.excuteBlock()

b = nil
a = nil
nested function
deinit a
deinit b

可以看到两个 object 的 deinit 都有调用到,个人理解 nested 和内联函数类似,只是方法的替换。

在编程中,函数内联 是一种编译器优化技术,它通过使用方法的内容替换直接调用该方法,就相当于假装该方法并不存在一样,这种做法在很大程度上优化了性能。

但是要注意,如果 nested function 中调用了外部方法,还是会造成循环引用:

import UIKit

class A {
    let b: B?
    
    init(b: B?) {
        self.b = b
    }
    
    deinit {
        print("deinit a")
    }
    
    func test() {
        func __nestedFunction() {
            test2()
            print("nested function")
        }
        b?.block = {
            __nestedFunction()
        }
    }
    
    func test2() {
        print("test 2")
    }
}

class B {
    var block: (() -> Void)?
    
    deinit {
        print("deinit b")
    }
    
    func excuteBlock() {
        block?()
    }
}

var b: B? = B()
var a: A? = A(b: b)
a?.test()
b?.excuteBlock()

b = nil
a = nil
test 2
nested function

为了防止隐性的循环引用,建议使用 block 或者把嵌套函数放到外面。