2013-06-19 55 views
83

我只是第一次進入iOS開發,我不得不做的第一件事就是實現一個custom container view controller - 我們稱之爲SideBarViewController - 它將幾個可能的子視圖控制器中的哪一個顯示,幾乎完全像標準標籤欄控制器。 (這是一個很值得標籤欄控制器但有可隱藏側邊菜單,而不是一個標籤欄。)addChildViewController實際上做了什麼?

按照蘋果的文檔中的說明,我所說的addChildViewController每當我添加一個子視圖控制器到我的容器。我換出當前子視圖控制器由SideBarViewController正在顯示的代碼如下所示:

- (void)showViewController:(UIViewController *)newViewController { 
    UIViewController* oldViewController = [self.childViewControllers 
              objectAtIndex:0]; 

    [oldViewController removeFromParentViewController]; 
    [oldViewController.view removeFromSuperview]; 

    newViewController.view.frame = CGRectMake(
     0, 0, self.view.frame.size.width, self.view.frame.size.height 
    ); 
    [self addChildViewController: newViewController]; 
    [self.view addSubview: newViewController.view]; 
} 

然後,我開始試圖找出正是addChildViewController在這裏所做的,我意識到,我不知道。除了在.childViewControllers陣列中粘貼新的ViewController之外,它似乎對任何內容都沒有影響。從子控制器的視圖到我在故事板上設置的子控制器的操作和插座仍然可以正常工作,即使我從未撥打過addChildViewController,我也無法想象會有什麼影響。

事實上,如果我重寫我的代碼不調用addChildViewController,而是這個樣子......

- (void)showViewController:(UIViewController *)newViewController { 

    // Get the current child from a member variable of `SideBarViewController` 
    UIViewController* oldViewController = currentChildViewController; 

    [oldViewController.view removeFromSuperview]; 

    newViewController.view.frame = CGRectMake(
     0, 0, self.view.frame.size.width, self.view.frame.size.height 
    ); 
    [self.view addSubview: newViewController.view]; 

    currentChildViewController = newViewController; 
} 

...然後我的應用程序仍然運轉完好,只要我可以告訴!

蘋果的文檔並沒有說明什麼addChildViewController做什麼,或爲什麼我們應該叫它。

將給定視圖控制器作爲子:什麼樣的方法執行或爲什麼它應在其部分被用於在UIViewController Class Reference的是,目前的相關描述的整個範圍。 ... 此方法僅用於通過自定義容器視圖控制器的實現進行調用。如果您重寫此方法,則必須在實現中調用super。

還有早些時候在同一頁面上這一段:

你的容器視圖控制器必須將孩子的根視圖到視圖層次結構前一個子視圖控制器與自身關聯。這允許iOS將事件正確地路由到子視圖控制器以及這些控制器管理的視圖。同樣,在從其視圖層次結構中刪除子視圖的根視圖之後,它應該將該子視圖控制器與其自身斷開連接。爲了建立或者中斷這些關聯,你的容器調用由基類定義的特定方法。這些方法不打算由您的容器類的客戶端調用;它們只能在您的容器的實施中使用,以提供預期的遏制行爲。

以下是你可能需要調用的基本方法:

addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:

,但它不提供任何線索,以什麼它所談論的'事件'或'預期的遏制行爲'是,或者爲什麼(甚至是何時)調用這些方法是'必不可少的'。

Apple文檔的「自定義容器視圖控制器」部分中的自定義容器視圖控制器的示例都調用此方法,所以我認爲它除了將子ViewController彈出到數組之外還有一些重要用途,但我無法弄清楚這是什麼目的。這種方法做什麼,爲什麼我應該叫它?

+3

蘋果[** 2011 ** WWDC(https://developer.apple.com/videos/wwdc/2011/)視頻頁面有關於此主題的_great_會話(「實現UIViewController遏制」)。 – Alladinian

回答

81

我也在想這個問題。我看着Session 102 of the WWDC 2011視頻和視圖控制器先生,Bruce D. Nilo對此表示:

viewWillAppear:viewDidAppear:,等什麼都沒有做addChildViewController:addChildViewController:所做的就是說「這個視圖控制器是那個視圖的子視圖」,它與視圖外觀無關。它們被調用時與視圖移入和移出窗口層次結構時相關聯。

因此,看起來addChildViewController:的呼叫確實很少。呼叫的副作用是重要的部分。他們來自parentViewControllerchildViewControllers的關係。這裏有一些副作用,我知道:

  • 轉發外觀的方法對兒童視圖控制器
  • 轉發旋轉方法
  • (可能)轉發內存警告
  • 避免不一致VC層次,特別是在transitionFromViewController:toViewController:…其中兩個VC需要具有相同的父項
  • 允許自定義容器視圖控制器參與狀態保存和恢復
  • T在響應鏈亞慶部分
  • 鉤住的navigationControllertabBarController等性質
+0

這是會議102不是101 – SeanChense

+0

+1爲響應者鏈。如果您想在子UIViewController擁有的子視圖上接收觸摸事件,則需要addChildViewController – charlieb

9

-[UIViewController addChildViewController:]只在ViewController(父級)想要引用的viewControllers數組中添加傳入的視圖控制器。實際上,您應該通過將其添加爲另一個視圖的子視圖(例如,parentViewController的視圖)來將這些viewController的視圖添加到屏幕上。在Interface Builder中還有一個便利對象,用於在Storyboard中使用childrenViewControllers。

以前,爲了保持您使用其視圖的其他viewController的引用,您必須在@properties中手動引用它們。如childViewControllers和因此parentViewController這樣的內置屬性是管理此類交互和構建組合viewController的便捷方式,例如您在iPad應用上找到的UISplitViewController。此外,childrenViewControllers還會自動接收父級接收的所有系統事件:-viewWillAppear,-viewWillDisappear等。以前,您應該在「childrenViewControllers」上手動調用此方法。

就是這樣。

+0

你認爲這就是它的所有基礎?另外,你能否提供一份由兒童接收的「系統事件」清單?谷歌搜索iOS系統事件並不會引起太多反響,它似乎不是Apple使用的術語? –

+0

它基本上是一種便利的方法,它允許您將View Controller B的視圖添加爲View Controller A的子視圖,但仍然使View Controller B管理其視圖。爲了使其正常工作,您需要確保View Controller B正在獲取系統事件(讀取UIViewControllerDelegate回調)。 'addChildViewController'爲您提供了這個功能,爲您節省了手動傳遞所有內容的工作量。 –

94

我認爲一個例子勝過千言萬語。

我正在研究一個圖書館應用程序,並希望顯示一個不錯的記事本視圖,當用戶想要添加一個筆記時出現。

enter image description here

嘗試一些解決方案之後,我最終發明了自己的自定義解決方案,以顯示記事本。所以當我想要顯示記事本時,我創建了一個NotepadViewController的新實例,並將它的根視圖作爲子視圖添加到主視圖。到現在爲止還挺好。

然後我注意到記事本圖像在橫向模式下部分隱藏在鍵盤下。

enter image description here

所以我想改變形象的記事本和移位起來。爲此,我在willAnimateRotationToInterfaceOrientation:duration:方法中編寫了正確的代碼,但是當我運行應用程序時什麼都沒有發生!調試後,我注意到UIViewController的旋轉方法實際上並沒有在NotepadViewController中調用。只有主視圖控制器中的那些方法正在被調用。

爲了解決這個問題,我需要在主視圖控制器中調用NotepadViewController時手動調用所有方法。這將很快使事情變得複雜,並在應用程序中無關組件之間創建額外的依賴關係。

這是過去,在引入子視圖控制器的概念之前。但是現在,您只需要addChildViewController即可使用主視圖控制器,一切都將按預期工作,而無需進行任何手動工作。

編輯: 有兩類事件轉發到子視圖控制器:

1-外觀方法:

- viewWillAppear: 
- viewDidAppear: 
- viewWillDisappear: 
- viewDidDisappear: 

2-旋轉方法:

- willRotateToInterfaceOrientation:duration: 
- willAnimateRotationToInterfaceOrientation:duration: 
- didRotateFromInterfaceOrientation: 

您還可以通過覆蓋來控制要自動轉發的事件類別和shouldAutomaticallyForwardAppearanceMethods

+0

從文檔和做一個快速測試後,我不認爲有任何其他事件只有在將'addChildViewController'添加到父控制器時才被轉發。 – Hejazi

+0

希望它自動轉發viewWillLayoutSubviews – MobileMon

相關問題