iPhone görünümü Ateşlemiyor


116

viewWillAppearGörüş hiyerarşinizi tam olarak oluşturmadığınızda sorun yaşayan insanlar hakkında çok sayıda yazı okudum . Benim sorunum bunun ne anlama geldiğini anlayamıyorum.

Bir denetleyiciyi oluşturup RootViewControllerçağırırsam addSubView, eklenen görünümlerin viewWillAppearolaylar için bağlanmasını beklerim.

viewWillAppearHer seviyede olayları başarıyla alan karmaşık bir programatik görünüm hiyerarşisine sahip olan var mı?

Apple'ın Dokümanlar durumu:

Uyarı: Bir görünüm denetleyicisine ait görünüm doğrudan bir görünüm hiyerarşisine eklenirse, görünüm denetleyicisi bu mesajı almaz. Görünüm hiyerarşisine bir görünüm ekler veya eklerseniz ve bunun bir görünüm denetleyicisi varsa, ilgili görünüm denetleyicisine bu mesajı doğrudan göndermelisiniz. Görünüm denetleyicisine bu mesajın gönderilmemesi, ilgili herhangi bir animasyonun görüntülenmesini engelleyecektir.

Sorun, bunun nasıl yapılacağını açıklamamalarıdır. "Doğrudan" ne anlama geliyor? Bir görünümü "dolaylı olarak" nasıl eklersiniz?

Cocoa ve iPhone'da oldukça yeniyim, bu nedenle temel Hello World saçmalıklarının yanı sıra Apple'dan faydalı örnekler olsaydı iyi olurdu.


Genel olarak UIViewController alt sınıflarının amaçlanan kullanımını yanlış anladığımı anlayana kadar bu sorunu yaşadım. Bu soruyu kontrol edin. stackoverflow.com/questions/5691226/…
averydev

7
Lütfen dikkat !!! İOS 5'te artık doğru değil !!! Aramalar görünümü Görünür ve görüntüleyinDidOtomatik olarak görünür
Vilém Kurz

Yanıtlar:


55

Bir gezinme denetleyicisi kullanıyorsanız ve temsilcisini ayarlarsanız, görünüm {Will, Did} {Appear, Disappear} yöntemleri çağrılmaz.

Bunun yerine gezinti denetleyicisi temsilci yöntemlerini kullanmanız gerekir:

navigationController:willShowViewController:animated:
navigationController:didShowViewController:animated:

2
Gezinme denetleyicimin temsilcisini ayarlamamıştım ve hala yöntem çağrılmıyordu. Neyse, ayarladım ve yukarıda bahsettiğiniz yöntemleri kullandım. Teşekkürler.
Dimitris

Dimitris ile aynı şeyi görüyorum
jkp

7
Bunu daha önce iOS4 ve iOS5'te test ettim: Bu doğru DEĞİL: Bir navigasyon
Kontrolörünün

Swift 3: (UIViewController, animasyon::: viewController willShow UINavigationController de, BOOL _ NavigationController) {} NavigationController fonk ve NavigationController fonk (_ NavigationController: UINavigationController, didShow viewController: UIViewController, hareketli: BOOL) {}
Naloiko Eugene

28

Aynı problemle karşılaştım. viewWillAppearAlt görünüm olarak eklemeden önce görünüm denetleyicinize bir mesaj göndermeniz yeterlidir. (Görünüm denetleyicisine animasyonun görünüp görünmeyeceğini söyleyen bir BOOL parametresi vardır.)

[myViewController viewWillAppear:NO];

Metronom örneğinde RootViewController.m'ye bakın.

(Aslında Apple'ın örnek projelerini harika buldum. HelloWorld'den çok daha fazlası var;)


3
Aslında, alt görünüme ekledikten sonra viewWillAppear'ı çağırmalısınız. Aksi takdirde, IBOutlets / IBActions bağlanmayacaktır.
4thSpace

2
Evet, daha sonra. XIB'den alt görünüm oluşturuldu, viewWillAppear çağrılmadı. Kendim diyorum ve her şey yolunda gidiyor.
JOM

Teşekkür ederim! Bu tam olarak benim için buydu. Üzerinden manuel olarak bir alt görünüm ekliyordum [scrollView addSubview:controller.view];. Satırı [controller viewWillAppear:NO];sonradan ekledim ve işte! Bir cazibe gibi çalıştı.
Rob S.

Büyük olasılıkla bunun nedeni, UIViewController'ınızın başka bir UIViewController tarafından kontrol edilen bir görünümün alt görünümü olan bir görünümü kontrol etmesidir. Bu, tasarlanan tasarım modeli değil. Daha fazla açıklama için bu gönderiye göz atın. stackoverflow.com/questions/5691226/…
averydev

6
Lütfen dikkat !!! İOS 5'te artık doğru değil !!! Aramalar otomatik olarak viewWillAppear ve viewDidAppear. Manuel olarak ararsanız, iki kez aranırdı.
Vilém Kurz

18

Sonunda ÇALIŞAN bunun için bir çözüm buldum!

UINavigationControllerDelegate

Bence bunun özü, nav kontrolünüzün temsilcisini içinde bulunduğu görüntü denetleyicisine ayarlamak ve uygulamak UINavigationControllerDelegateve bu iki yöntemi uygulamaktır. Parlak! Sonunda bir çözüm bulduğum için çok heyecanlıyım!


bir rootview denetleyicisini gezinti denetleyicisi için temsilci olarak nasıl atayabilirim?
Gargo

1
İŞE YARAMIYOR! uygulamayı küçültmeyi ve maksimize etmeyi deneyin
Vyachaslav Gerchicov

8

Ben de aynı sorunu yaşadım. Benim uygulamamda 2 gezinme denetleyicim var ve her birinde aynı görüntü denetleyicisine basmak, bir durumda çalışırken diğerinde değil. Ben ilk tam aynı görünüm denetleyicisi bastırıyor zaman anlamına UINavigationController, viewWillAppearikinci gezinme denetleyicisi itilmiş çağrılan ancak değildi.

Sonra bu gönderiye rastladım UINavigationController, viewWillAppear / viewWillDisappear yöntemlerini çağırmalı

Ve ikinci gezinme denetleyicimin yeniden tanımladığını fark ettim viewWillAppear. Kodu taramak aramadığımı gösterdi

[super viewWillAppear:animated];

Ben ekledim ve işe yaradı!

Belgeler şunu söylüyor:

Bu yöntemi geçersiz kılarsanız, uygulamanızın bir noktasında super'i çağırmanız gerekir.


Aynı şey burada. Süper çağırmayarak berbat.
olivaresF

5

Gezinme denetleyicisi kullanıyorum. Başka bir veri düzeyine inmek veya özel görünümümü göstermek istediğimde aşağıdakileri kullanıyorum:

[self.navigationController pushViewController:<view> animated:<BOOL>];

Bunu yaptığımda, viewWillAppearateşleme işlevini alıyorum . Sanırım bu "dolaylı" olarak nitelendiriliyor çünkü gerçek addSubViewyöntemi kendim demiyorum. Gezinme denetleyicisi kullanıp kullanmadığınızı söyleyemediğim için bunun uygulamanız için% 100 uygulanabilir olup olmadığını bilmiyorum, ancak belki bir ipucu sağlayabilir.


5

Teşekkürler iOS 13.

ViewWillDisappear, ViewDidDisappear, ViewWillAppearVe ViewDidAppeartüm ekranı kapsamaz yeni modal sunu kullandığı iOS 13 üzerinde sunulması görünüm denetleyicisi çağrısında almazsınız.

Krediler Arek Holko'ya gidiyor . Günümü gerçekten kurtardı.

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


4

Öncelikle, sekme çubuğu Apple belgelerinde belirtildiği gibi kök seviyesinde olmalı, yani pencereye eklenmelidir. Bu, doğru davranış için anahtardır.

İkincisi, yapabilirsiniz kullanmak UITabBarDelegate/ UINavigationBarDelegatemanuel bildirim iletmek için, ama doğru çalışması için görünüm aramaların bütün hiyerarşi almak bulundu, tüm Ben elle aramayı yapmak zorunda

[tabBarController viewWillAppear:NO];
[tabBarController viewDidAppear:NO];

ve

[navBarController viewWillAppear:NO];
[navBarController viewDidAppear:NO];

.. ilgili kontrol cihazındaki görünüm kontrolörlerini kurmadan hemen önce (tahsisattan hemen sonra). O andan itibaren, bu yöntemleri çocuk görüntüleme denetleyicilerinde doğru bir şekilde çağırdı.

Benim hiyerarşim şöyle:

window
    UITabBarController (subclass of)
        UIViewController (subclass of) // <-- manually calls [navController viewWill/DidAppear
            UINavigationController (subclass of)
                UIViewController (subclass of) // <-- still receives viewWill/Did..etc all the way down from a tab switch at the top of the chain without needing to use ANY delegate methods

Sadece sekme / gezinme denetleyicisinde belirtilen yöntemleri ilk kez çağırmak, TÜM olayların doğru şekilde iletilmesini sağladı. Onları UINavigationBarDelegate/ UITabBarControllerDelegateyöntemlerinden manuel olarak çağırmamı engelledi .

Sidenote: Merakla, işe yaramadığında, özel yöntem

- (void)transitionFromViewController:(UIViewController*)aFromViewController toViewController:(UIViewController*)aToViewController 

.. çalışan bir uygulamadaki çağrı yığınından görebileceğiniz, genellikle viewWill/Did..yöntemleri çağırır, ancak yukarıdakileri gerçekleştirene kadar (çağrılsa bile).

Sanırım UITabBarControllerpencere düzeyinde olması ÇOK önemli ve belgeler bunu destekliyor gibi görünüyor.

Umarım bu açıktı (imsi), başka soruları yanıtlamaktan mutluluk duyarım.


3

Hiçbir cevap kabul edilmediğinden ve insanlar (benim yaptığım gibi) buraya indiğinden varyasyonumu veriyorum. Asıl sorunun bu olduğundan emin değilim. Gezinme denetleyicisi başka bir görünüme alt görünüm olarak eklendiğinde, viewWillAppear / Dissappear vb. Yöntemlerini şu şekilde çağırmanız gerekir:

- (void) viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [subNavCntlr viewWillAppear:animated];
}

- (void) viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [subNavCntlr viewWillDisappear:animated];
}

Sadece örneği tamamlamak için. Bu kod, gezinme denetleyicisini oluşturduğum ve görünüme yerleştirdiğim bir görünüme eklediğim ViewController'ımda görünüyor.

- (void)viewDidLoad {

    // This is the root View Controller
    rootTable *rootTableController = [[rootTable alloc]
                 initWithStyle:UITableViewStyleGrouped];

    subNavCntlr = [[UINavigationController alloc]   
                  initWithRootViewController:rootTableController];

    [rootTableController release];

    subNavCntlr.view.frame = subNavContainer.bounds;

    [subNavContainer addSubview:subNavCntlr.view];

    [super viewDidLoad];
}

.h şuna benzer

@interface navTestViewController : UIViewController <UINavigationControllerDelegate> {
    IBOutlet UIView *subNavContainer;
    UINavigationController *subNavCntlr;
}

@end

Uç dosyasında görünüme sahibim ve bu görüntünün altında bir resim ve denetleyiciyi koyduğum kap (başka bir görünüm) var. Görünüşü burada. Bu bir müşteri için çalıştığı için bazı şeyleri karıştırmam gerekiyordu.

alternatif metin


3

Görünümler "doğrudan" arayarak eklenir [view addSubview:subview]. Görünümler, alt görünümleri değiştiren sekme çubukları veya gezinme çubukları gibi yöntemlerle "dolaylı olarak" eklenir.

Her aradığınızda [view addSubview:subviewController.view], aramanız gerekir [subviewController viewWillAppear:NO](veya duruma göre EVET).

Bir oyundaki bir alt ekran için kendi özel kök görünümü yönetim sistemimi uyguladığımda bu sorunu yaşadım. Aramayı viewWillAppear'a manuel olarak eklemek sorunumu çözdü.


3

Bunu yapmanın doğru yolu, UIViewController çevreleme api'sini kullanmaktır.

- (void)viewDidLoad {
     [super viewDidLoad];
     // Do any additional setup after loading the view.
     UIViewController *viewController = ...;
     [self addChildViewController:viewController];
     [self.view addSubview:viewController.view];
     [viewController didMoveToParentViewController:self];
}

Bu kesinlikle doğru modern çözümdür (iOS 9,8,7). Ayrıca, yerleşik görünüm denetleyicisini anında değiştiriyorsanız, [viewController willMoveToParentViewController: nil] 'i çağırmanız gerekir; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController];
Eli Burke

1
Bu durumda viewWillAppear: hala çağrılmayabilir
Vyachaslav Gerchicov

2

Bu kodu push ve pop görünüm denetleyicileri için kullanıyorum:

it:

[self.navigationController pushViewController:detaiViewController animated:YES];
[detailNewsViewController viewWillAppear:YES];

pop:

[[self.navigationController popViewControllerAnimated:YES] viewWillAppear:YES];

.. ve benim için iyi çalışıyor.


2

Çok yaygın bir hata aşağıdaki gibidir. Bir görünümünüz var UIView* ave bir tane daha var UIView* b. A'yı alt görünüm olarak eklersiniz. B'de viewWillAppear'ı çağırmaya çalışırsanız, hiçbir zaman ateşlenmeyecektir çünkü bu a'nın bir alt görünümüdür.


2

iOS 13 uygulamamı burada kıçtan ısırdı. İOS 13'ten itibaren davranış değişikliği fark ettiyseniz, itmeden önce aşağıdakileri ayarlayın:

yourVC.modalPresentationStyle = UIModalPresentationFullScreen;

Ayrıca, Öznitelikler denetçisindeki .storyboard'unuzda da ayarlamanız gerekebilir (Sunumu Tam Ekran olarak ayarlayın).

Bu, uygulamanızın önceki iOS sürümlerinde olduğu gibi davranmasını sağlayacaktır.


1

Bundan% 100 emin değilim, ancak görünüm hiyerarşisine bir görünüm eklemenin -addSubview:, [viewController.view addSubview:anotherViewController.view]yeni bir görünüm denetleyicisini gezinme denetleyicisinin yığınına itmek yerine doğrudan görünüm denetleyicisinin görünümünü (örneğin ) çağırmak anlamına geldiğini düşünüyorum .


1

Bir alt görünüm eklemenin, görünümün mutlaka görüneceği anlamına gelmediğini düşünüyorum, bu nedenle sınıfın yöntemine otomatik bir çağrı olmayacaktır.


1

Sanırım "doğrudan" demek istedikleri şeyleri xcode "Gezinme Uygulaması" şablonunun yaptığı gibi bağlayarak UINavigationController'ı uygulamanın UIWindow'unun tek alt görünümü olarak ayarlıyor.

Bu şablonu kullanmak, UINavigationController'daki bu denetleyicilerin push / pop'ları üzerine ViewControllers nesnesinde çağrılan Will / Did / Appear / Disappear yöntemlerini alabilmemin tek yoluydu. Buradaki yanıtlardaki diğer çözümlerin hiçbiri benim için işe yaramadı, bunları RootController'da uygulamak ve onları (alt) NavigationController'a geçirmek dahil. Bu işlevler (olacak / göründü / göründü / kayboldu) yalnızca en üst düzey VC'ler, "oturum açma" ve navigasyonVC'lerim gösterildiğinde / gizlendiğinde, gezinme denetleyicisindeki alt VC'ler değil, RootController'imde çağrıldı, bu yüzden hiçbir fırsatım olmadı onları Nav VC'ye "iletin".

Uygulamamda takip işlevselliği gerektiren ve işe yarayan belirli geçişleri aramak için UINavigationController'ın temsilci işlevini kullanmaya son verdim, ancak hem kaybolma hem de görünme işlevselliğini "simüle" elde etmek için biraz daha fazla çalışma gerekiyor.

Ayrıca bugün saatlerce bu soruna karşı kafamı çarptıktan sonra çalışmasını sağlamak da bir prensip meselesi. Özel bir RootController ve bir alt gezinme VC kullanan çalışan herhangi bir kod parçacığı çok takdir edilecektir.


1

Bu kimseye yardımcı olursa diye. Ben benim de benzer bir sorun vardı ViewWillAppearbir ateş değildir UITableViewController. Etrafta çok oynadıktan sonra, sorunun UINavigationControllerbenim kontrolümün UITableViewkök görünümünde olmaması olduğunu fark ettim . Bunu düzelttikten sonra, artık bir şampiyon gibi çalışıyor.


Bunu nasıl yaptığınızı lütfen paylaşır mısınız?
Brabbeldas 01

1

Bu sorunu henüz kendim yaşadım ve düzeltmem 3 tam saatimi (2'si googling) aldı.

Yardımcı olduğu ortaya çıkan şey , uygulamayı cihazdan / simülatörden silmek, temizlemek ve ardından tekrar çalıştırmaktı .

umarım yardımcı olur


1
[self.navigationController setDelegate:self];

Temsilciyi kök görünüm denetleyicisine ayarlayın.


1

Swift için. Önce, görünümde aramak istediğiniz şeyi çağırmak için protokolü oluşturun

protocol MyViewWillAppearProtocol{func myViewWillAppear()}

İkincisi, sınıfı oluşturun

class ForceUpdateOnViewAppear: NSObject, UINavigationControllerDelegate {
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool){
    if let updatedCntllr: MyViewWillAppearProtocol = viewController as? MyViewWillAppearProtocol{
        updatedCntllr.myViewWillAppear()
    }
}

}

Üçüncü olarak, ForceUpdateOnViewAppear örneğini, Gezinme Denetleyicisine erişimi olan ve Gezinti denetleyicisi var olduğu sürece var olan uygun sınıfın üyesi yapın. Örneğin, gezinme denetleyicisinin kök görünüm denetleyicisi veya onu oluşturan veya sunan sınıf olabilir. Ardından, ForceUpdateOnViewAppear örneğini Gezinme Denetleyicisi delegate özelliğine olabildiğince erken atayın.


0

Benim durumumda sorun, özel geçiş animasyonuyla oldu. Ayarlandığında modalPresentationStyle = .custom viewWillAppearçağrılmaz

özel geçiş animasyonu sınıfında çağrı yöntemlerine ihtiyaç vardır: beginAppearanceTransitionveendAppearanceTransition


0

Benim durumumda bu, ios 12.1 öykünücüsündeki garip bir hataydı. Gerçek cihazda başlatıldıktan sonra kayboldu.


0

Bu sorunu çözen bir sınıf oluşturdum. Bunu gezinme denetleyicinizin bir temsilcisi olarak ayarlayın ve görünüm denetleyicinizde basit bir veya iki yöntem uygulayın - bu, görünüm gösterilmek üzereyken veya NavigationController aracılığıyla gösterildiğinde çağrılır.

İşte kodu gösteren GIST


0

ViewWillAppear, UIViewController sınıfının bir geçersiz kılma yöntemidir, bu nedenle bir subView eklemek viewWillAppear'ı çağırmaz, ancak bir viewController'dan sunduğunuzda, push, pop, show, setFront veya popToRootViewController ve ardından sunulan viewController için viewWillAppear çağrılır.


0

Sorunum, bir segmentten çözülürken viewWillAppear'ın çağrılmamasıydı. Cevap, geri döndüğünüz View Controller içindeki çözülme segmentine viewWillAppear (true) için bir çağrı koymaktı.

@IBAction func çözme (wrindSegue için: UIStoryboardSegue, ViewController laterVC: Any) {

   viewWillAppear(true)
}

-2

Çözdüğüm sorunun bu olduğundan emin değilim.
Bazı durumlarda, yöntem "[self methodOne]" gibi normal yollarla yürütülmez.

Deneyin

- (void)viewWillAppear:(BOOL)animated
{
    [self performSelector:@selector(methodOne) 
           withObject:nil afterDelay:0];
}

sorun viewWillAppearhiç çağrılmıyor
Vyachaslav Gerchicov

-3

Herhangi bir zamanda yalnızca 1 UIViewController etkin olmalıdır. Değiştirmek istediğiniz tüm alt görünümler tam olarak böyle olmalıdır - subVIEWS - yani UIView.

Bakış hiyerarşimi yönetmek için basit bir teknik kullanıyorum ve işleri bu şekilde yapmaya başladığımdan beri henüz bir sorunla karşılaşmadım. 2 önemli nokta vardır:

  • uygulamanızın "bir ekran değerini" yönetmek için tek bir UIViewController kullanılmalıdır
  • görünümleri değiştirmek için UINavigationController'ı kullanın

"Bir ekranın değeri" ile ne demek istiyorum? Kasıtlı olarak biraz belirsiz, ancak genellikle uygulamanızın bir özelliği veya bölümüdür. Aynı arka plan görüntüsüne, ancak farklı kaplamalar / açılır pencerelere vb. Sahip birkaç ekranınız varsa, bu 1 görünüm denetleyicisi ve birkaç alt görünüm olmalıdır. Kendinizi asla 2 görünüm denetleyicisiyle çalışırken bulmamalısınız. Yine de bir görünüm denetleyicisinde bir UIView örneğini oluşturabilir ve ekranın belirli alanlarının birden çok görünüm denetleyicisinde gösterilmesini istiyorsanız onu başka bir görünüm denetleyicisinin alt görünümü olarak ekleyebileceğinizi unutmayın.

UINavigationController'a gelince - bu sizin en iyi arkadaşınız! Gezinme çubuğunu kapatın ve animasyonlu için HAYIR'ı belirtin ve talep üzerine ekranlar arasında geçiş yapmanın mükemmel bir yolunu elde edin. Bir hiyerarşide iseler görünüm denetleyicileri itebilir ve açabilirsiniz veya bir dizi görünüm denetleyicisi (tek bir VC içeren bir dizi dahil) hazırlayabilir ve setViewControllers kullanarak bunu görünüm yığını olarak ayarlayabilirsiniz. Bu size VC'leri değiştirme özgürlüğü verirken, Apple'ın beklenen modeli dahilinde çalışmanın ve tüm olayları vb. Doğru şekilde çalıştırmanın tüm avantajlarını elde etmenizi sağlar.

Bir uygulamayı her başlattığımda yaptığım şey şu:

  • pencere tabanlı bir uygulamadan başlayın
  • pencerenin rootViewController'ı olarak bir UINavigationController ekleyin
  • ilk UIViewController'imin nav denetleyicisinin rootViewController'ı olmasını istediğimi ekle

(pencere tabanlıdan başlamak sadece kişisel bir tercihtir - Bir şeyleri kendim oluşturmayı seviyorum, böylece nasıl inşa edildiklerini tam olarak bilirim. Görünüm tabanlı şablonla iyi çalışması gerekir)

Tüm olaylar doğru şekilde tetiklenir ve temelde hayat iyidir. Ardından, tüm zamanınızı uygulamanızın önemli parçalarını yazarak ve görünüm hiyerarşilerini manuel olarak şekillendirmeye çalışmakla uğraşmadan harcayabilirsiniz.


Birden çok görüntü denetleyicisinin etkin olmasının yanlış bir tarafı yoktur; UIViewController, bir hiyerarşinin oluşturulmasına izin veren yöntemlere sahiptir (örn. [AddChildViewController:]).
Richard

1
Evet şimdi öyle. 2011'de olmadı. Cevap o zamanlar doğruydu, kuşkusuz şimdi değil.
Nigel Flack
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.