ios – Swift强参考周期的令人困惑的例子

这是 Apple’s document的一个例子:
class HTMLElement {

    let name: String
    let text: String?

    lazy var asHTML: Void -> String = {
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String,text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) is being deinitialized")
    }

}

我明白为什么这个关闭属性会导致强大的参考周期,我知道如何解决它.我不会争辩这个.

真正让我感到困惑的是以下代码:

var heading: HTMLElement? = HTMLElement(name: "h1")
let defaultText = "some default text"
heading!.asHTML = {
    // confusing,this closure are supposed to retain heading here,but it does not
    return "<\(heading!.name)>\(heading!.text ?? defaultText)</\(heading!.name)>"
}
print(heading!.asHTML())
heading = nil
// we can see the deinialization message here,// it turns out that there is not any strong reference cycle in this snippet.

据我所知,从Swift documentation和我自己的Objective-c经验来看,变量标题将被关闭所捕获,因此应该引起很强的参考周期.但是没有,这真的让我感到困惑.

我也写了一个这个例子的Objective-C对应的,它确实引起了我的预期的很强的参考周期.

typedef NSString* (^TagMaker)(void);

@interface HTMLElement : NSObject

@property (nonatomic,strong) NSString      *name;
@property (nonatomic,strong) NSString      *text;

@property (nonatomic,strong) TagMaker      asHTML;

@end

@implementation HTMLElement

- (void)dealloc {
    NSLog(@"%@",[NSString stringWithFormat:@"%@ is being deinitialized",self.name]);
}

@end

;

HTMLElement *heading = [[HTMLElement alloc] init];
heading.name = @"h1";
heading.text = @"some default text";

heading.asHTML = ^ {
    return [NSString stringWithFormat:@"<%@>%@</%@>",heading.name,heading.text,heading.name];
};

NSLog(@"%@",heading.asHTML());

heading = nil;
// heading has not been deinitialized here

任何提示或指导将不胜感激.

解决方法

因为在后来的情况下

快速关闭持有强烈的标题,而不是标题的实例

在一个图像中,它显示为这样

如果我们通过set heading = nil打破红线,那么引用圆就被打破了.

更新开始:

但是,如果你没有设置为零,仍然有一个引用圈,像我上面发布的图像.你可以像这样测试

func testCircle(){
    var heading: HTMLElement? = HTMLElement(name: "h1")
    let defaultText = "some default text"
    heading.asHTML = {
        return "<\(heading.name)>\(heading.text ?? defaultText)</\(heading.name)>"
    }
    print(heading.asHTML())
}
testCircle()//No dealloc message is printed

更新结束

我还写下面的测试代码来证明闭包不能强烈地引用内存中的实例

var heading: HTMLElement? = HTMLElement(name: "h1")
var heading2 = heading
let defaultText = "some default text"
heading!.asHTML = {
// confusing,but it does not
    return "<\(heading!.name)>\(heading!.text ?? defaultText)</\(heading!.name)>"
}
let cloureBackup = heading!.asHTML
print(heading!.asHTML())

heading = HTMLElement(name: "h2")

print(cloureBackup())//<h2>some default text</h2>

所以,测试代码的形象是

你会从操场看到日志

<h1>some default text</h1>
<h2>some default text</h2>

没有找到任何关于这个的文件,只是从我的测试和理解,希望这将是有益的

相关文章

当我们远离最新的 iOS 16 更新版本时,我们听到了困扰 Apple...
欧版/美版 特别说一下,美版选错了 可能会永久丧失4G,不过只...
一般在接外包的时候, 通常第三方需要安装你的app进行测...
前言为了让更多的人永远记住12月13日,各大厂都在这一天将应...