强引用和 UIView 内存问题
Strong references and UIView memory issues
我正在处理一些无法解决的重新分配问题,也许是强引用或循环引用。我有三个 UIView
s 实例化如下:
有一个主 ViewController
,我在故事板中添加了一个 UIView
,UIView
在 class 中有一个 weak
出口喜欢:
class ViewController : UIViewController {
//MARK: - outlets
@IBOutlet weak var firstView: FirstUiview!
}
second UIView
作为子视图以编程方式添加到第一个视图,如:
class FirstUiview : UIView {
//creating an instance of secondUiView
lazy var mySecondView: SecondViewClass = {
let dv = SecondViewClass()
dv.backgroundColor = UIColor.red
return dv
}()
//sometime later by clicking on a button
self.addSubview(mySecondView)
//a button will be tapped to remove mySecondView;
//later will be called at some point upon tapping:
func removingSecondViewByTapping() {
if mySecondView.isDescendant(of: self) {
mySecondView.removeFromSuperview()
}
}
}
现在 SecondViewClass
是:
class SecondViewClass : UIView {
//in this class I create bunch of uiview objects like below:
lazy var aView : UIView = {
let hl = UIView()
hl.tag = 0
hl.backgroundColor = UIColor.lightGray
return hl
}()
self.addSubview(aView) //... this goes on and I add other similar views the same way.
//creating an instance of thirdView
var let thirdView = UIView()
self.addSubview(thirdView)
}
现在,如果用户点击按钮删除 mySecondView
,然后在其他时间再次添加它(仍然在同一个 ViewController
中),我希望 mySecondView
的所有子视图已经被释放并消失了,但他们都在那里。如果有人能指出我在哪里保留强引用或者是否存在循环引用问题,我将不胜感激?或者别的什么?
您有两个对视图的强引用,您的自定义 属性 和调用 addSubview
时建立的视图层次结构引用。当您从视图层次结构中删除视图时,您的 class 本身仍然具有对它的强引用。
您可以通过将您的引用设置为可选来解决这个问题,并且当您调用 removeFromSuperview
时,也可以手动将您的引用设置为 nil
。或者,也许更简单,您可以通过使用 weak
引用来解决此问题,让视图层次结构为您维护强引用。并且由于您的自定义 属性 是 weak
,当您将其从视图层次结构中删除时(从而消除了对它的唯一强引用),您的 weak
引用将自动变为 nil
:
class FirstView: UIView {
weak var secondView: SecondView? // note the `weak` reference, which is obviously an optional
//sometime later by clicking on a button
func doSomething() {
let subview = SecondView()
subview.backgroundColor = .red
self.addSubview(subview)
secondView = subview
}
// a button will be tapped to remove secondView;
// later will be called at some point upon tapping ...
func removingSecondViewByTapping() {
secondView?.removeFromSuperview()
}
}
我正在处理一些无法解决的重新分配问题,也许是强引用或循环引用。我有三个 UIView
s 实例化如下:
有一个主 ViewController
,我在故事板中添加了一个 UIView
,UIView
在 class 中有一个 weak
出口喜欢:
class ViewController : UIViewController {
//MARK: - outlets
@IBOutlet weak var firstView: FirstUiview!
}
second UIView
作为子视图以编程方式添加到第一个视图,如:
class FirstUiview : UIView {
//creating an instance of secondUiView
lazy var mySecondView: SecondViewClass = {
let dv = SecondViewClass()
dv.backgroundColor = UIColor.red
return dv
}()
//sometime later by clicking on a button
self.addSubview(mySecondView)
//a button will be tapped to remove mySecondView;
//later will be called at some point upon tapping:
func removingSecondViewByTapping() {
if mySecondView.isDescendant(of: self) {
mySecondView.removeFromSuperview()
}
}
}
现在 SecondViewClass
是:
class SecondViewClass : UIView {
//in this class I create bunch of uiview objects like below:
lazy var aView : UIView = {
let hl = UIView()
hl.tag = 0
hl.backgroundColor = UIColor.lightGray
return hl
}()
self.addSubview(aView) //... this goes on and I add other similar views the same way.
//creating an instance of thirdView
var let thirdView = UIView()
self.addSubview(thirdView)
}
现在,如果用户点击按钮删除 mySecondView
,然后在其他时间再次添加它(仍然在同一个 ViewController
中),我希望 mySecondView
的所有子视图已经被释放并消失了,但他们都在那里。如果有人能指出我在哪里保留强引用或者是否存在循环引用问题,我将不胜感激?或者别的什么?
您有两个对视图的强引用,您的自定义 属性 和调用 addSubview
时建立的视图层次结构引用。当您从视图层次结构中删除视图时,您的 class 本身仍然具有对它的强引用。
您可以通过将您的引用设置为可选来解决这个问题,并且当您调用 removeFromSuperview
时,也可以手动将您的引用设置为 nil
。或者,也许更简单,您可以通过使用 weak
引用来解决此问题,让视图层次结构为您维护强引用。并且由于您的自定义 属性 是 weak
,当您将其从视图层次结构中删除时(从而消除了对它的唯一强引用),您的 weak
引用将自动变为 nil
:
class FirstView: UIView {
weak var secondView: SecondView? // note the `weak` reference, which is obviously an optional
//sometime later by clicking on a button
func doSomething() {
let subview = SecondView()
subview.backgroundColor = .red
self.addSubview(subview)
secondView = subview
}
// a button will be tapped to remove secondView;
// later will be called at some point upon tapping ...
func removingSecondViewByTapping() {
secondView?.removeFromSuperview()
}
}