[英]Can I use willSet and/or didSet to trigger a transition to a new view controller based on the value of a variable?
[英]Does this view controller leak in a “willSet/didSet” pair?
您有一個vc(綠色),並且有一個面板(黃色)“持有人”
假設您有十種不同的視圖控制器...價格,銷售,庫存,卡車,駕駛員,調色板,您將一次將它們放置在黃色區域中。 它將從情節提要中動態加載每個VC
instantiateViewController(withIdentifier: "PricesID") as! Prices
我們將保持當前的VC之一current
。 這是允許您在它們之間“交換”的代碼...
必須做Sulthan在下面解釋的事情。
var current: UIViewController? = nil {
willSet {
// recall that the property name ("current") means the "old" one in willSet
if (current != nil) {
current!.willMove(toParentViewController: nil)
current!.view.removeFromSuperview()
current!.removeFromParentViewController()
// "!! point X !!"
}
}
didSet {
// recall that the property name ("current") means the "new" one in didSet
if (current != nil) {
current!.willMove(toParentViewController: self)
holder.addSubview(current!.view)
current!.view.bindEdgesToSuperview()
current!.didMove(toParentViewController: self)
}
}
}
還要注意,如果您執行這樣的操作,則在完成綠色頁面后,必須擺脫黃色視圖控制器。 否則, current
將保留它,並且永遠不會釋放綠色頁面:
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
current = nil
super.dismiss(animated: flag, completion: completion)
}
繼續,您將使用如下所示的current
屬性:
func showPrices() {
current = s.instantiateViewController(withIdentifier: "PricesID") as! Prices
}
func showSales() {
current = s.instantiateViewController(withIdentifier: "SalesID") as! Sales
}
但是考慮一下,注意“點X” 。 通常,您必須將要擺脫的視圖控制器設置為nil。
blah this, blah that
blah.removeFromParentViewController()
blah = nil
但是我(不要認為)您可以在“ willSet”代碼塊中真正將current設置為nil。 而且我很欣賞它即將被設置為某種東西(在didSet中)。 但這似乎有些奇怪。 缺少了什么? 您甚至可以在計算屬性中執行此類操作嗎?
使用Sulthan的方法,在經過大量測試后,此方法可以完美地工作。
所以這樣叫
// change yellow area to "Prices"
current = s.instantiateViewController(withIdentifier: "PricesID") as! Prices
// change yellow area to "Stock"
current = s.instantiateViewController(withIdentifier: "StickID") as! Stock
這很好用...
var current: UIViewController? = nil { // ESSENTIAL to nil on dismiss
didSet {
guard current != oldValue else { return }
oldValue?.willMove(toParentViewController: nil)
if (current != nil) {
addChildViewController(current!)
holder.addSubview(current!.view)
current!.view.bindEdgesToSuperview()
}
oldValue?.view.removeFromSuperview()
oldValue?.removeFromParentViewController()
if (current != nil) {
current!.didMove(toParentViewController: self)
}
}
// courtesy http://stackoverflow.com/a/41900263/294884
}
override func dismiss(animated flag: Bool, completion: (() -> Void)? = nil) {
// ESSENTIAL to nil on dismiss
current = nil
super.dismiss(animated: flag, completion: completion)
}
讓我們將問題分為兩個部分:(1)是否存在“泄漏”? (2)這是個好主意嗎?
首先是“泄漏”。 簡短的回答:不。 即使您未將current
設置為nil
,它所持有的視圖控制器也顯然不會“泄漏”; 當包含的視圖控制器不存在時, current
指向的視圖控制器也將消失。
但是, current
視圖控制器的壽命確實比需要的更長。 因此,這似乎很愚蠢。 不需要對子視圖控制器的強大參考current
,因為畢竟它是您的childViewControllers[0]
(如果您正確執行了子視圖控制器的“跳舞”)。 因此,您僅使用屬性復制childViewControllers
屬性已經執行的操作。
這就引出了第二個問題:您在做一個好主意嗎? 不,我知道您來自哪里,您想封裝子視圖控制器的“舞蹈”。 但是無論如何,您的舞步都不正確。 因此,您正在顛覆視圖控制器層次結構。 為了封裝“舞蹈”,我會說,您最好正確地進行舞蹈並提供執行該舞蹈的功能 ,以及提供了引用childViewController[0]
已計算只讀屬性(如果存在)。
在這里,我假設我們一次只能擁有一個子視圖控制器; 我認為這樣做要好得多:
var current : UIViewController? {
if self.childViewControllers.count > 0 {
return self.childViewControllers[0]
}
return nil
}
func removeChild() {
if let vc = self.current {
vc.willMove(toParentViewController: nil)
vc.view.removeFromSuperview()
vc.removeFromParentViewController()
}
}
func createChild(_ vc:UIViewController) {
self.removeChild() // There Can Be Only One
self.addChildViewController(vc) // *
// ... get vc's view into the interface ...
vc.didMove(toParentViewController: self)
}
我不認為使用didSet
實際上是錯誤的。 但是,最大的問題是您試圖在willSet
和didSet
之間拆分代碼,因為willSet
didSet
。 您可以始終在didSet
使用oldValue
:
var current: UIViewController? = nil {
didSet {
guard current != oldValue else {
return
}
oldValue?.willMove(toParentViewController: nil)
if let current = current {
self.addChildViewController(current)
}
//... add current.view to the view hierarchy here...
oldValue?.view.removeFromSuperview()
oldValue?.removeFromParentViewController()
current?.didMove(toParentViewController: self)
}
}
順便說一下,函數的調用順序很重要。 因此,我不建議將功能拆分為remove
和add
。 否則,這兩個控制器的viewDidDisappear
和viewDidAppear
的順序可能令人驚訝。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.