带有计时器的类的UIView可以防止deinit

时间:2018-04-06 18:08:51

标签: swift

我不确定这是否是最好的设计设置,但我现在有类似的东西:

class MyView: UIView {

    var nextView: NextView?

    override func layoutSubviews() {
    super.layoutSubviews()
        nextView = NextView()
        nextView!.go()
    }

    deinit {
        print("call me")
    }

}

class NextView {

    var timer: Timer?

    func go() { 
        timer = Timer.scheduledTimer(withTimeInterval: 1,
                                 repeats: true,
                                 block: { [weak self] _ in })
    }

    deinit {
        print("call me")
        timer?.invalidate()
        timer = nil
    }
}

使用此设置,在UIViewController从根UIViewController更改后,MyView和NextView不会取消初始化。如果我将var nextView更改为弱var nextView,则会在类加载后调用deinitializers,但nextView为nil。函数go()不会被调用。

如何在MyView处于取消初始化状态的UIViewController中取消初始化这两个类,还会取消?

1 个答案:

答案 0 :(得分:0)

您的NextView未被取消初始化的原因是,在此设置中,MyView拥有NextView的强引用(且只有一个)。如果您将其设为weak引用,则任何强引用都不会保留NextView,并且会立即取消初始化。

内存在经典UI层次结构中的工作方式如下:一个视图对每个子视图都有一个强引用,而对于它的超视图则是一个弱引用。这可以防止保留周期,同时允许删除视图到级联"所有子视图的去初始化。

默认情况下,使用方法addSubview会自动创建此强引用,如documentation中所述。

  

此方法建立了一个强大的引用来查看并设置其接收器的下一个响应者,这是它的新超级视图。

因此,在您的情况下执行此操作的好方法是使用MyView

中的以下内容更新代码
override func layoutSubviews() {
    super.layoutSubviews()
    nextView = NextView()
    addSubview(nextView)
    nextView!.go()
}

希望有所帮助!

我不想过多评论代码本身,因为这不是主题,但我很确定在layoutSubviews中创建子视图是一个糟糕的主意。

同样在您的情况下,您每次都会重新创建此视图,这可能在计算上非常昂贵。如果您只想创建一次,请使用

override func layoutSubviews() {
    super.layoutSubviews()

    if nextView == nil {
        nextView = NextView()
        addSubview(nextView)
        nextView!.go()
    }
}