<UITabBarController: 0x197870> için görünüm geçişlerini başlatmak / bitirmek için dengesiz çağrılar


119

Benzer bir hatayla karşılaşan başka bir kullanıcı hakkında SO okudum , ancak bu hata farklı durumda.

Başlangıçta bir Görünüm Kontrolcüsü eklediğimde bu mesajı aldım:

Unbalanced calls to begin/end appearance transitions for 
<UITabBarController: 0x197870>

Uygulamanın yapısı aşağıdaki gibidir:

5 Görünüm Denetleyicisine bağlı 5 sekmeli bir TabBarController var. İlk gösterim sekmesinde, uygulamanın tanıtımı olarak üst üste bindirmek için yeni bir Görünüm Denetleyicisini çağırıyorum.

Bu kodu, giriş görünümü denetleyicisini çağırmak için kullanıyorum:

IntroVC *vc = [[IntroVC alloc] init];
[self presentModalViewController:vc animated:YES];
[vc release]; 

Bu IntroVCgörüntü denetleyicisi göründükten sonra, yukarıdaki hata gösterilir.

ps xCode 4.2 ve iOS 5.0 SDK kullanıyorum, iOS 4.3 uygulaması geliştiriyorum.


Merhaba Shivan, seninle aynı problemim var. Ama yine de aşağıdaki cevapları gördükten sonra düzeltemiyorum. Giriş görünümü denetleyicisini nerede aradığınızı öğrenebilir miyim?
ZYiOS

Yanıtlar:


98

Çevreleyen kodu daha fazla görmeden kesin bir cevap veremem, ancak iki teorim var.

  1. Kullanmadığınız UIViewController's başlatıcı belirlenmişinitWithNibName:bundle: . Sadece kullanmak yerine kullanmayı deneyin init.

  2. Ayrıca, selfsekme çubuğu denetleyicisinin görünüm denetleyicilerinden biri olabilir. Görünüm denetleyicilerini her zaman en üstteki görünüm denetleyicisinden sunun; bu, bu durumda sekme çubuğu denetleyicisinden görünüm denetleyicisi adına bindirme görünüm denetleyicisini sunmasını isteyin. Yine de herhangi bir geri arama temsilcisini gerçek görünüm denetleyicisine tutabilirsiniz, ancak sekme çubuğu denetleyicisinin mevcut olması ve kapatılması gerekir.


2
# 1 bu sorunu benim için çözdüm, initWithNibName: nil bundle: nil yerine init kullandım.
Hua-Ying

172
Bu uyarıyı, uygulama başlatılmadan önce modal vc'yi sunarak oluşturabilirsiniz. Örneğin, sekmeli bir uygulama şablonu uygulamasını başlatın ve uygulamadaki son satır olarak self.tabBarController'ın üstünde bir modal vc sunun: didFinishLaunching. Uyarı belirir. Çözüm: Önce yığının çözülmesine izin verin, modal vc'yi başka bir yöntemde sunun, Gecikme: 0.0 ile bir performSelector ile çağrılır.
danh

9
Ve işte başka bir soru performSelector withDelay'in neden çalıştığını açıklıyor. stackoverflow.com/questions/1922517/…
fatih

1
danh'ın çözümü benim için çalıştı, ancak 0,0 yerine 0,1 kullanmak zorunda kaldım.
Brandon O'Rourke

11
Sıfır değerinde bir performSelectorWithDelay kullanmak yerine, bunu viewDidLoad veya whatnot yerine viewDidAppear içinde gerçekleştirin.
tooluser

40

Bu hatayı animasyonlu YES'ten HAYIR'a değiştirerek düzelttim.

Gönderen:

[tabBarController presentModalViewController:viewController animated:YES];

Kime:

[tabBarController presentModalViewController:viewController animated:NO];

4
Bu, animasyonu
önemsemiyorsanız

3
Bilginize: presentModalViewController: animated: iOS6'da kullanımdan kaldırıldı.
ZS

16

Danh tarafından yayınlandığı gibi

Bu uyarıyı, uygulama başlatılmadan önce modal vc'yi sunarak oluşturabilirsiniz. Örneğin, sekmeli bir uygulama şablonu uygulamasını başlatın ve uygulamadaki son satır olarak self.tabBarController'ın üstünde bir modal vc sunun: didFinishLaunching. Uyarı belirir. Çözüm: Önce yığının çözülmesine izin verin, modal vc'yi başka bir yöntemde sunun, gecikmeli bir performSelector ile çağrılır: 0.0

Yöntemi viewWillAppear'a taşımayı deneyin ve sadece bir kez çalıştırılması için onu koruyun (bir özellik ayarlamanızı tavsiye ederiz)


Neden viewWillAppearve değil viewDidAppear?
CyberMew

6

Pek çok durum için başka bir çözüm de, aşağıdakileri yaparak uygun olmayan (başlatma sırasında olduğu gibi) yordam bittikten sonraUIViewController s arasındaki geçişin gerçekleşmesini sağlamaktır :

__weak MyViewController *weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
    [weakSelf presentViewController:vc animated:YES];
});

Bu pushViewController:animated:, vb. İçin de geneldir .


4

Ben de aynı sorunu yaşadım. viewDidLoadİlk içimde bir yöntem çağırdımUIViewController

- (void)viewDidLoad{
    [super viewDidLoad];

    [self performSelector:@selector(loadingView)
               withObject:nil afterDelay:0.5];
}

- (void)loadingView{

    [self performSegueWithIdentifier:@"loadedData" sender:self];
}

Saniyede UIViewController0.5 saniye gecikmeyle de aynısını yaptım. Gecikmeyi daha yüksek bir değere değiştirdikten sonra iyi çalıştı. Sanki bölüm, başka bir bölümden sonra çok hızlı gerçekleştirilemez.


7
Görünüm yaşam döngüsü yöntemi viewDidAppear tam olarak bu amaç için sağlanmıştır ve yapay bir gecikme, fwiw sunmaktan daha güvenilir olacaktır.
tooluser

1
Navigasyon denetleyicisinin yeni bir navigasyona hazır olmasını beklemek için 0'lık bir gecikme yeterli olması dışında bu doğru cevaptır.
malhal

Tamamen doğru, onu içeri çağırmalısın, viewDidAppearböylece UINavigationControlleronunla başa çıkmaya hazırsın.
Gönderimi

Bunun WillAppear'a taşınması gerektiğini düşünüyorum, o zaman görünümün başlatılıp başlatılmadığı konusunda endişelenmenize gerek yok.
jokeyi

3

Oturum Açma Görüntüleme Denetleyicimi başka bir Görüntü Denetleyicisinden Sunmam gerektiğinde aynı sorunu yaşadım Eğer Kullanıcı yetkilendirilmemişse, bunu Başka Bir Görüntü Denetleyicimin ViewDidLoad Yönteminde yaptım (yetkili değilse -> presentModalViewController). ViewDidAppear yönteminde yapmaya başladığımda bu sorunu çözdüm. ViewDidLoad'un sadece özellikleri başlattığını düşünüyorum ve bundan sonra gerçek görüntüleme algoritması başlıyor! İşte bu yüzden mod geçişleri yapmak için viewDidAppear yöntemini kullanmalısınız!


3

Bu sorunu bir yazım hatası nedeniyle yaşadım:

override func viewDidAppear(animated: Bool) {
    super.viewWillAppear(animated)

onun yerine

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

"DidAppear" yerine süperde "WillAppear" diyordu.


2

Aynı sorunla ilgili çok sorun yaşadım. Bunu çözdüm

  1. Storyboad instantiateViewControllerWithIdentifier yöntemini kullanarak ViewController'ı başlatma. yaniIntro *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"introVC"];
  2. [self.tabBarController presentModalViewController : vc animated:YES];

Görüntü denetleyicisini film şeridimde, bazı nedenlerden dolayı yalnızca [[introvc alloc] init]; işe yaramadı.


1
Sizi yeni görsel senaryo taslağı özelliğini kullanırken görmek güzel. ama benim durumumda film şeridi kullanmıyordum ...
Raptor

Sadece "instantiateViewControllerWithIdentifier" ın denetleyicinin Tanımlayıcısını aldığını belirtmek istedim. daha fazla ayrıntı için stackoverflow.com/questions/8186375/…
adresini ziyaret

2

Yazarak çözdüm

[self.navigationController presentViewController:viewController 
                                        animated:TRUE 
                                      completion:NULL];

3
Bilginize, daha deyimsel (ve daha güvenli!)
Olmak için

2
Size daha deyimsel bir ifade vereceğim ama bu nasıl daha güvenli?
Zev Eisenberg

2

Bu sorunu üçüncü taraf bir kodla yaşadım. Birisi özel bir TabBarController sınıfında viewWillAppear ve viewWillDisappear'ın süper içini ayarlamayı unuttu.

- (void) viewWillAppear:(BOOL)animated {

    [super viewWillAppear:animated];
    // code...
}

or

- (void) viewWillDisappear:(BOOL)animated {

    [super viewWillDisappear:animated];
    // code...
}

2

Eğer kullanıyorsanız transitioningDelegate(bu Sorunun örnekte değil durum), ayrıca set modalPresentationStyleiçin .Custom.

hızlı

let vc = storyboard.instantiateViewControllerWithIdentifier("...")
vc.transitioningDelegate = self
vc.modalPresentationStyle = .Custom

1

Ben de aynı hatayı aldım. 3 öğeli bir sekme çubuğum var ve bilinçsizce kullanarak sekme çubuğumun 2. öğesindeki öğe 1'in kök görünüm denetleyicisini çağırmaya çalışıyordum performSegueWithIdentifier.

Olan şey, görünüm denetleyicisini çağırması ve birkaç saniye sonra öğe 2'nin kök görünüm denetleyicisine geri dönmesi ve bu hatayı günlüğe kaydetmesidir.

Görünüşe göre, bir öğenin kök görünüm denetleyicisini başka bir öğeye çağıramazsınız.

Yani yerine performSegueWithIdentifier

kullandım [self.parentViewController.tabBarController setSelectedIndex:0];

Umarım bu birine yardımcı olur.


1

Aynı sorunu yaşadım ve başka birinin benzer bir şeyle karşılaşması durumunda göndereceğimi düşündüm.

Benim durumumda, UITableViewController'ıma uzun bir basma hareketi tanıyıcı ekledim.

UILongPressGestureRecognizer *longPressGesture = [[[UILongPressGestureRecognizer alloc]
                                                   initWithTarget:self
                                                   action:@selector(onLongPress:)]
                                                  autorelease];
[longPressGesture setMinimumPressDuration:1];
[self.tableView addGestureRecognizer:longPressGesture];

OnLongPress seçicimde, sonraki görünüm denetleyicimi başlattım.

- (IBAction)onLongPress:(id)sender {

    SomeViewController* page = [[SomeViewController alloc] initWithNibName:@"SomeViewController" bundle:nil];

    [self.navigationController pushViewController:page animated:YES];

    [page release];

}

Benim durumumda, hata mesajını aldım çünkü uzun basma tanıyıcı birden fazla kez ateşledi ve sonuç olarak "SomeViewController" yığına birden çok kez itildi.

Çözüm, SomeViewController'ın yığına ne zaman itildiğini belirtmek için bir boole eklemekti. UITableViewController'ın viewWillAppear yöntemi çağrıldığında, boole değerini NO olarak ayarladım.


1

Bir storyboard kullanıyorsanız, yeni görünüm denetleyicisini sunan kodu viewDidAppear'a koymak isteyeceğinizi buldum. Ayrıca, "Ayrılmış görünüm denetleyicilerinde görünüm denetleyicilerinin sunulması önerilmez" uyarısından da kurtulacaktır.


1

In 2+ Swift beni çalışır için:

Film şeridinde UITabBarViewController var ve bunun gibiIndex özelliğini seçtim:

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

Ama onu siliyorum ve ilk sınıfımın viewDidLoad yöntemine şu şekilde ekliyorum:

override func viewDidLoad() {
   super.viewDidLoad()
   self.tabBarController?.selectedIndex = 2
}

Umarım birine yardım edebilirim.


0

Aslında itme animasyonu bitene kadar beklemelisin. Böylece UINavigationController'ı yetkilendirebilir ve animasyon bitene kadar itmeyi engelleyebilirsiniz.

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    waitNavigation = NO;
}


-(void)showGScreen:(id)gvc{

    if (!waitNavigation) {
        waitNavigation = YES;
        [_nav popToRootViewControllerAnimated:NO];
        [_nav pushViewController:gvc animated:YES];
    }
}

Bir hücre seçildiğinde ararım. Aslında sana bağlı
ymutlu

0

@Danh'ın önerdiği gibi benim sorunum modal vc'yi UITabBarControllerhazır olmadan önce sunmamdı . Bununla birlikte, görüntüleme denetleyicisini sunmadan önce sabit bir gecikmeye güvenmekten rahatsızlık duydum (testlerime göre 0,05-0,1 sn gecikme kullanmam gerekiyordu performSelector:withDelay:). Benim çözümüm üzerinde çağrılan bir blok eklemektir UITabBarControllerbireyin viewDidAppear:yöntemiyle:

PRTabBarController.h:

@interface PRTabBarController : UITabBarController

@property (nonatomic, copy) void (^viewDidAppearBlock)(BOOL animated);

@end

PRTabBarController.m:

#import "PRTabBarController.h"

@implementation PRTabBarController

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    if (self.viewDidAppearBlock) {
        self.viewDidAppearBlock(animated);
    }
}

@end

Şimdi application:didFinishLaunchingWithOptions:

PRTabBarController *tabBarController = [[PRTabBarController alloc] init];

// UIWindow initialization, etc.

__weak typeof(tabBarController) weakTabBarController = tabBarController;
tabBarController.viewDidAppearBlock = ^(BOOL animated) {
    MyViewController *viewController = [MyViewController new];
    viewController.modalPresentationStyle = UIModalPresentationOverFullScreen;
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
    [weakTabBarController.tabBarController presentViewController:navigationController animated:NO completion:nil];
    weakTabBarController.viewDidAppearBlock = nil;
};

0

emin olmanız gerekir - (void) beginAppearanceTransition: (BOOL) canlandırılmış görünmektedir: (BOOL) animasyonlu ve - (void) endAppearanceTransition sınıfta birlikte oluşturulur.


0

Ben de aynı sorunu yaşadım. Geliştirme sırasında ekranları atlamak istedim. Bir seçici yöntemi çağırarak viewDidLoad'da bir görünüm denetleyicisinden diğerine gidiyorum.

Sorun şu ki, başka bir ViewController'a geçmeden önce ViewController'ın geçişi bitirmesine izin vermeliyiz.

Bu, sorunumu çözdü: Gecikme, ViewControllers'ın bir başkasına geçmeden önce geçişi bitirmesine izin vermek için gereklidir.

self.perform(#selector(YOUR SELECTOR METHOD), with: self, afterDelay: 0.5)

0

Swift 5

 func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {


//Delete or comment the below lines on your SceneDelegate.

//        guard let windowScene = (scene as? UIWindowScene) else { return }
//        window?.windowScene = windowScene
//        window?.makeKeyAndVisible()

        let viewController = ListVC()
        let navViewController = UINavigationController(rootViewController: viewController)
        window?.rootViewController = navViewController

    }

-1

Kök TVC'den TVC A'ya, ardından TVC B'ye geçerken bu sorunu yaşadım. TVC BI'daki "yükle" düğmesine dokunduktan sonra, doğrudan kök TVC'ye geri dönmek istedim (TVC A'yı tekrar ziyaret etmeye gerek yok, öyleyse neden yapalım) . Sahiptim:

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:YES];
//Pop self to return to root
[self.navigationController popViewControllerAnimated:YES];

... "Dengesiz çağrılar başlamak / bitirmek vb." hatasını verdi. Aşağıdaki hata düzeltildi, ancak animasyon yok:

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:NO];
//Then pop self to return to root
[self.navigationController popViewControllerAnimated:NO];

Bu benim son çözümümdü, hata yok ve hala animasyonlu

//Pop child from the nav controller
[self.navigationController popViewControllerAnimated:NO];
//Then pop self to return to root, only works if first pop above is *not* animated
[self.navigationController popViewControllerAnimated:YES];

-1

Bir UIButton'u bir storyboard segue eylemine (IB'de) bağladığımda bu hatayla karşılaştım, ancak daha sonra düğmeyi programatik olarak çağırmaya karar verdim performSegueWithIdentifier olarak ilkini IB'den kaldırmak için unutma .

Temelde, segment çağrısını iki kez gerçekleştirdi, bu hatayı verdi ve aslında görüşümü iki kez zorladı. Düzeltme, segment çağrılarından birini kaldırmaktı.

Umarım bu benim kadar yorgun birine yardımcı olur!

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.