Bu hat:
[self dismissViewControllerAnimated:YES completion:nil];
kendisine bir mesaj göndermiyor, aslında sunum yapan VC'sine bir mesaj gönderiyor ve işten çıkarmayı yapmasını istiyor. Bir VC sunduğunuzda, sunum yapan VC ile sunulan VC arasında bir ilişki oluşturursunuz. Bu nedenle, sunum sırasında mevcut VC'yi yok etmemelisiniz (sunulan VC, bu kapatma mesajını geri gönderemez…). Bunu gerçekten hesaba katmadığınız için uygulamayı şaşkın bir durumda bırakıyorsunuz. Cevabıma bakın
Bu yöntemin daha açık bir şekilde yazılmasını önerdiğim Sunulan bir Görüntü Denetleyicisini Kapatma :
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Sizin durumunuzda, tüm kontrollerin yapıldığından emin olmanız gerekir mainVC
. Doğru mesajı ViewController1'den MainViewController'a geri göndermek için bir temsilci kullanmanız gerekir, böylece mainVC, VC1'i kapatabilir ve sonra VC2'yi sunabilir.
In VC2 VC1 @interface yukarıdaki .h dosyasında bir protokol ekleyin:
@protocol ViewController1Protocol <NSObject>
- (void)dismissAndPresentVC2;
@end
ve @interface bölümünde aynı dosyada daha aşağıya, temsilci işaretçisini tutmak için bir özellik bildirin:
@property (nonatomic,weak) id <ViewController1Protocol> delegate;
VC1 .m dosyasında, reddetme düğmesi yöntemi temsilci yöntemini çağırmalıdır
- (IBAction)buttonPressedFromVC1:(UIButton *)sender {
[self.delegate dissmissAndPresentVC2]
}
Şimdi mainVC'de, VC1'i oluştururken onu VC1'in temsilcisi olarak ayarlayın:
- (IBAction)present1:(id)sender {
ViewController1* vc = [[ViewController1 alloc] initWithNibName:@"ViewController1" bundle:nil];
vc.delegate = self;
[self present:vc];
}
ve temsilci yöntemini uygulayın:
- (void)dismissAndPresent2 {
[self dismissViewControllerAnimated:NO completion:^{
[self present2:nil];
}];
}
present2:
VC2Pressed:
Düğme IBAction yönteminizle aynı yöntem olabilir . VC2'nin VC1 tamamen kapatılıncaya kadar sunulmamasını sağlamak için tamamlama bloğundan çağrıldığını unutmayın.
Şimdi VC1-> VCMain-> VC2'den hareket ediyorsunuz, bu nedenle muhtemelen geçişlerden yalnızca birinin animasyonlu olmasını isteyeceksiniz.
Güncelleme
Yorumlarınızda, görünüşte basit olan bir şeyi başarmak için gereken karmaşıklığa şaşkınlık ifade ediyorsunuz. Sizi temin ederim, bu yetkilendirme modeli Objective-C ve Cocoa'nın çoğu için çok merkezi ve bu örnek alabileceğiniz en basit şeyle ilgili, gerçekten rahat olmak için çaba göstermelisiniz.
Apple'ın View Controller Programming Guide'da şunları söyleyecekler :
Sunulan Bir Görünüm Denetleyicisini Kapatma
Sunulan bir görüntü denetleyicisini reddetme zamanı geldiğinde, tercih edilen yaklaşım, sunan görünüm denetleyicisinin onu reddetmesine izin vermektir. Diğer bir deyişle, mümkün olduğunda, görüş denetleyicisini sunan aynı görüş denetleyicisi, onu reddetme sorumluluğunu da almalıdır. Sunulan görünüm denetleyicisine sunulan görünüm denetleyicisinin atılması gerektiğini bildirmek için birkaç teknik olmasına rağmen, tercih edilen teknik yetkilendirmedir. Daha fazla bilgi için bkz. "Diğer Denetleyicilerle İletişim Kurmak için Temsilciliğin Kullanılması."
Eğer gerçekten neyi başarmak istediğinizi ve bunu nasıl yapacağınızı gerçekten düşünürseniz, bir NavigationController kullanmak istemediğinizde, MainViewController'ınıza tüm işi yapması için mesaj göndermenin tek mantıklı çıkış yolu olduğunu fark edeceksiniz. Eğer varsa yapmak bir NavController kullanmak, aslında sen bile değil açıkça eğer iş yapmak için navController için, 'delege' vardır. Orada olması gereken bazı görüntülü konferans navigasyon neler merkezi izler nesne ve ihtiyacınız bazı ne yaparsanız onunla iletişim yöntemini.
Pratikte Apple'ın tavsiyesi biraz aşırıdır ... normal durumlarda, özel bir temsilci ve yöntem oluşturmanıza gerek yoktur, güvenebilirsiniz [self presentingViewController] dismissViewControllerAnimated:
- sizinki gibi durumlarda, işten çıkarılmanızın uzaktan kumanda üzerinde başka etkileri olmasını istersiniz. dikkat etmeniz gereken nesneler.
İşte tüm delege güçlüğü olmadan çalışmayı hayal edebileceğiniz bir şey ...
- (IBAction)dismiss:(id)sender {
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:^{
[self.presentingViewController performSelector:@selector(presentVC2:)
withObject:nil];
}];
}
Sunum denetleyicisinden bizi görevden almasını rica ettikten sonra, VC2'yi çağırmak için presentingViewController'da bir yöntemi çağıran bir tamamlama bloğumuz var. Temsilciye gerek yok. (Blokların büyük bir satış noktası, bu koşullarda delege ihtiyacını azaltmalarıdır). Ancak bu durumda yolumuza çıkan birkaç şey var ...
- VC1 sen yok biliyorum mainVC yöntemini uygulayan
present2
- Zor debug hata veya çöker ile sona erebilir. Delegeler bundan kaçınmanıza yardımcı olur.
- VC1 bir kez reddedildiğinde, tamamlama bloğunu yürütmek için gerçekten ortalıkta değil ... yoksa değil mi? Self.presentingViewController artık bir şey ifade ediyor mu? Bilmiyorsunuz (ben de bilmiyorum) ... bir delege ile, bu belirsizliğe sahip değilsiniz.
- Bu yöntemi çalıştırmaya çalıştığımda, hiçbir uyarı veya hata olmadan kilitleniyor.
Bu yüzden lütfen ... yetkilendirmeyi öğrenmek için zaman ayırın!
güncelleme2
Yorumunuzda, bunu VC2'nin kapat düğmesi işleyicisinde kullanarak çalışmasını sağlamayı başardınız:
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
Bu kesinlikle çok daha basit, ancak size bir takım sorunlar bırakıyor.
Sıkı kaplin
ViewController yapınızı birlikte kabloluyorsunuz. Örneğin, mainVC'den önce yeni bir viewController eklerseniz, gerekli davranışınız bozulur (öncekine gidersiniz). VC1'de ayrıca # VC2'yi içe aktarmanız gerekiyor. Bu nedenle, OOP / MVC hedeflerini bozan oldukça fazla karşılıklı bağımlılığınız var.
Temsilcileri kullanarak, ne VC1 ne de VC2'nin mainVC veya öncülleri hakkında hiçbir şey bilmesine gerek kalmaz, bu nedenle her şeyi gevşek bağlı ve modüler tutuyoruz.
Bellek
VC1 gitmedi, hala ona iki işaretçi tutuyorsunuz:
- mainVC'nin
presentedViewController
mülkü
- VC2'nin
presentingViewController
özelliği
Bunu günlüğe kaydederek ve ayrıca bunu VC2'den yaparak test edebilirsiniz.
[self dismissViewControllerAnimated:YES completion:nil];
Hala çalışıyor, yine de sizi VC1'e geri götürüyor.
Bu bana bir hafıza sızıntısı gibi görünüyor.
Bunun ipucu, burada aldığınız uyarıda:
[self presentViewController:vc2 animated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
Aşağı mantık kırılırsa, sunu VC görevden çalıştığınız olarak hangi VC2 takdim VC olduğunu. İkinci mesaj gerçekten uygulanmıyor - belki bazı şeyler oluyor, ancak yine de kurtulduğunuzu düşündüğünüz bir nesneye iki işaretçi kalıyorsunuz. ( düzenle - Bunu kontrol ettim ve o kadar da kötü değil, mainVC'ye döndüğünüzde her iki nesne de kayboluyor )
Bu oldukça uzun soluklu bir söylem - lütfen delegeleri kullanın. İşe yarayacaksa, burada kalıbın başka bir kısa açıklamasını yaptım:
Bir denetçiden bir denetleyiciyi geçirmek her zaman kötü bir uygulama mıdır?
güncelleme 3
Temsilcilerden gerçekten kaçınmak istiyorsanız, bu en iyi çıkış yolu olabilir:
VC1'de:
[self presentViewController:VC2
animated:YES
completion:nil];
Ama hiçbir şeyi göz ardı etmeyin ... bizim de belirlediğimiz gibi, aslında zaten olmuyor.
VC2'de:
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
Biz (biliyorum) biz VC1 çıkarmadık, biz geri ulaşabilir aracılığıyla VC1 için MainVC. MainVC, VC1'i kapatır. VC1 gittiği için, VC2'nin onunla birlikte geldiği sunuldu, böylece MainVC'ye temiz bir durumda geri döndünüz.
VC1'in VC2 hakkında bilmesi gerektiğinden ve VC2'nin buna MainVC-> VC1 aracılığıyla ulaşıldığını bilmesi gerektiğinden, hala oldukça bağlantılı, ancak biraz açık yetkilendirme olmadan elde edeceğiniz en iyisi bu.