AddChildViewController gerçekte ne yapar?


102

Ayaklarımı ilk kez iOS geliştirmeye yatırıyorum ve yapmam gereken ilk şeylerden biri, olası birkaç çocuk görüntüleme denetleyicisinden hangisini değiştiren özel bir kapsayıcı görünümü denetleyicisi uygulamaktı - hadi SideBarViewControllerdiyelim - neredeyse tamamen standart bir Sekme Çubuğu Denetleyicisi gibi gösterir . (Hemen hemen bir Sekme Çubuğu Denetleyicisi, ancak sekme çubuğu yerine gizlenebilir bir yan menüye sahip.)

Apple belgelerindeki talimatlara göre, addChildViewControllerkapsayıcıma her çocuk ViewController eklediğimde arıyorum . Mevcut çocuk görüntüleme denetleyicisini değiştirmek için kodum şu şekilde SideBarViewControllergörünüyor:

- (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];
}

Sonra addChildViewControllerburada ne olduğunu anlamaya çalıştım ve hiçbir fikrim olmadığını anladım. Yeni yapışmasını yanında ViewControlleryer .childViewControllersdizide, o şey üzerinde hiçbir etkisi var gibi gözüküyor. Çocuk denetleyicinin görüşünden, film şeridinde belirlediğim alt denetleyiciye kadar eylemler ve çıkışlar, hiç aramasam bile hala gayet iyi çalışıyor addChildViewControllerve başka neleri etkileyebileceğini hayal edemiyorum.

Nitekim, kodumu arama yapmamak için yeniden yazarsam addChildViewControllerve bunun yerine şöyle görünürsem ...

- (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;
}

... o zaman, anlayabildiğim kadarıyla uygulamam hala mükemmel çalışıyor!

Apple belgeleri, neyin addChildViewControllerişe yaradığına veya neden onu çağırmamız gerektiğine pek ışık tutmuyor. Yöntemin ne yaptığına veya neden UIViewControllerSınıf Referansındaki bölümünde kullanılması gerektiğine ilişkin ilgili açıklamanın tüm kapsamı şu anda:

Verilen görünüm denetleyicisini alt öğe olarak ekler. ... Bu yöntemin yalnızca özel bir konteyner görünümü denetleyicisinin uygulaması tarafından çağrılması amaçlanmıştır. Bu yöntemi geçersiz kılarsanız, uygulamanızda super'i çağırmanız gerekir.

Aynı sayfada daha önce şu paragraf var:

Kapsayıcı görünümü denetleyiciniz, çocuğun kök görünümünü görünüm hiyerarşisine eklemeden önce bir çocuk görünümü denetleyicisini kendisiyle ilişkilendirmelidir. Bu, iOS'un olayları çocuk görüntüleme denetleyicilerine ve bu denetleyicilerin yönettiği görünümlere doğru şekilde yönlendirmesine olanak tanır. Benzer şekilde, bir çocuğun kök görünümünü görünüm hiyerarşisinden çıkardıktan sonra, bu çocuk görünümü denetleyicisinin kendisiyle olan bağlantısını kesmelidir. Bu ilişkilendirmeleri yapmak veya bozmak için, kapsayıcınız temel sınıf tarafından tanımlanan belirli yöntemleri çağırır. Bu yöntemlerin, konteyner sınıfınızın istemcileri tarafından çağrılması amaçlanmamıştır; bunlar, yalnızca konteynerinizin uygulaması tarafından beklenen muhafaza davranışını sağlamak için kullanılacaktır.

İşte aramanız gerekebilecek temel yöntemler:

addChildViewController:
removeFromParentViewController
willMoveToParentViewController:
didMoveToParentViewController:

ancak bahsettiği "olayların" veya "beklenen sınırlama davranışının" ne olduğuna veya bu yöntemleri çağırmanın neden (veya hatta ne zaman) "gerekli" olduğuna dair herhangi bir ipucu sunmaz.

Apple belgelerinin "Özel Kap Görünümü Denetleyicileri" bölümündeki özel kap görünümü denetleyicileri örneklerinin tümü bu yöntemi çağırıyor, bu nedenle alt ViewController'ı bir diziye yerleştirmenin ötesinde bazı önemli bir amaca hizmet ettiğini varsayıyorum, ancak anlayamıyorum bu amacın ne olduğunu öğrenin. Bu yöntem ne işe yarar ve neden onu çağırmalıyım?


3
Apple'ın 2011 WWDC videoları sayfasında bu konuyla ilgili harika bir oturum ("UIViewController Muhafazasını Uygulama") var.
Alladinian

Yanıtlar:


94

Ben de bu soruyu merak ediyordum. WWDC 2011 videolarının 102. Oturumunu izledim ve Mr. View Controller, Bruce D. Nilo şunları söyledi:

viewWillAppear:, viewDidAppear:vb addChildViewController:. ile hiçbir ilgisi yoktur . Tek addChildViewController:yaptığı, "Bu görünüm denetleyicisi, bunun alt öğesi" demek ve görünüm görünümüyle hiçbir ilgisi yok. Ne zaman çağrıldıklarında, görünümlerin pencere hiyerarşisine girip çıkmasıyla ilişkilendirilir.

Görünüşe göre çağrı addChildViewController:çok az şey yapıyor. Aramanın yan etkileri önemli kısımdır. parentViewControllerVe childViewControllersilişkilerinden gelirler . İşte bildiğim bazı yan etkiler:

  • Görünüm yöntemlerini alt görünüm denetleyicilerine iletme
  • Yönlendirme rotasyon yöntemleri
  • (Muhtemelen) bellek uyarılarını iletme
  • Tutarsız VC hiyerarşilerinden kaçınmak, özellikle transitionFromViewController:toViewController:…her iki VC'nin de aynı ebeveyni olması gerektiği durumlarda
  • Özel konteyner görünümü denetleyicilerinin Durum Koruma ve Geri Yükleme'de yer almasına izin verme
  • Müdahale zincirinde yer almak
  • Çengel navigationController, tabBarControllervb özelliklerini

Oturum 102 101 değil
SeanChense

Yanıtlayıcı zinciri için +1. UIViewController alt görünümüne ait bir alt görünümde dokunma olaylarını almak istiyorsanız addChildViewController gereklidir
charlieb

108

Bence bir örnek bin kelimeye bedeldir.

Bir kitaplık uygulaması üzerinde çalışıyordum ve kullanıcı bir not eklemek istediğinde ortaya çıkan güzel bir not defteri görünümü göstermek istedim.

görüntü açıklamasını buraya girin

Bazı çözümleri denedikten sonra, not defterini göstermek için kendi özel çözümümü icat ettim. Bu yüzden not defterini göstermek istediğimde, yeni bir örnek oluşturup NotepadViewControllerkök görünümünü ana görünüme bir alt görünüm olarak ekliyorum. Çok uzak çok iyi.

Sonra yatay modda not defteri görüntüsünün kısmen klavyenin altına gizlendiğini fark ettim.

görüntü açıklamasını buraya girin

Bu yüzden not defteri görüntüsünü değiştirmek ve yukarı kaydırmak istedim. Ve bunu yapmak için, willAnimateRotationToInterfaceOrientation:duration:yöntemde doğru kodu yazdım , ancak uygulamayı çalıştırdığımda hiçbir şey olmadı! Ve hata ayıklamadan sonra, UIViewControllerrotasyon yöntemlerinden hiçbirinin aslında çağrılmadığını fark ettim NotepadViewController. Yalnızca ana görünüm denetleyicisindeki yöntemler çağrılır.

Bunu çözmek için, tüm yöntemleri aramam gerekiyordu. NotepadViewController , ana görünüm denetleyicisinde çağrıldıklarında manuel . Bu, yakında işleri karmaşık hale getirecek ve uygulamadaki ilgisiz bileşenler arasında fazladan bir bağımlılık yaratacaktır.

Bu geçmişte, çocuk görüş denetleyicileri kavramı tanıtılmadan önceydi. Ancak şimdi, yalnızca addChildViewControllerana görüntü denetleyicisine ihtiyacınız var ve her şey daha fazla manuel çalışma gerektirmeden beklendiği gibi çalışacak.

Düzenle: Çocuk görünümü denetleyicilerine iletilen iki olay kategorisi vardır:

1- Görünüm Yöntemleri:

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

2- Rotasyon Yöntemleri:

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

Otomatik olarak iletilmesini istediğiniz olay kategorilerini shouldAutomaticallyForwardRotationMethodsve öğelerini geçersiz kılarak da kontrol edebilirsiniz shouldAutomaticallyForwardAppearanceMethods.


Dokümantasyondan ve hızlı bir test yaptıktan sonra, yalnızca addChildViewControllerana denetleyiciye ilettiğiniz başka bir olay olduğunu düşünmüyorum .
Hicazi

viewWillLayoutSubviews
MobileMon

10

-[UIViewController addChildViewController:]yalnızca bir viewController (üst öğe) başvurusunu tutmak istediği bir viewControllers dizisine geçirilen görünüm denetleyicisini ekler. Aslında bu viewController görünümlerini başka bir görünümün alt görünümleri (örneğin parentViewController görünümü) olarak ekleyerek ekrana kendiniz eklemelisiniz. Arabirim Oluşturucu'da, Storyboard'larda childrenViewControllers'ı kullanmak için bir kolaylık nesnesi de vardır.

Önceden, görünümlerini kullandığınız diğer viewControllers referanslarını tutmak için, @properties içinde bunların manuel referansını tutmanız gerekiyordu. Bir yap-gibi mülkiyet olması childViewControllersdolayısıyla ve parentViewControlleriPad uygulamalar üzerinde bulmak böyle etkileşimleri ve UISplitViewController gibi inşa oluşan viewControllers yönetmek için uygun bir yoldur.

Ayrıca, childrenViewControllers ayrıca ebeveynin aldığı tüm sistem olaylarını otomatik olarak alır: -viewWillAppear, -viewWillDisappear, vb. Daha önce bu yöntemleri "childrenViewControllers" üzerinde manuel olarak çağırmış olmalısın.

Bu kadar.


Tüm yaptıklarının bu olduğunu düşünmenin temeli nedir? Ayrıca, çocuk tarafından alınan 'sistem olaylarının' bir listesini verebilir misiniz? Bir Google araması iOS "system events"çok fazla sonuç vermez; Apple'ın kullandığı bir terim değil mi?
Mark Amery

Temelde, View Controller B'nin görünümünü View Controller A'nın bir alt görünümü olarak eklemenize, ancak View Controller B'nin görünümünü yönetmesine izin veren bir kolaylık yöntemidir. Bunun düzgün çalışması için, View Controller B'nin sistem olaylarını aldığından emin olmanız gerekir (UIViewControllerDelegate geri aramalarını okuyun). 'addChildViewController', her şeyi manuel olarak iletme çabasından tasarruf etmenizi sağlamak için bunu sizin için bağlar.
Sam Clewlow
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.