AppDelegate'ten hikaye tahtasının farklı yerlerinde koşullu olarak başlayın


107

Çalışan oturum açma ve ana görünüm denetleyicisiyle oluşturulmuş bir film şeridim var, ikincisi, oturum açma başarılı olduğunda kullanıcının yönlendirildiği görünüm denetleyicisidir. Amacım, kimlik doğrulama (anahtar zincirinde saklanan) başarılı olursa ana görünüm denetleyicisini hemen göstermek ve kimlik doğrulama başarısız olursa oturum açma görünümü denetleyicisini göstermektir. Temel olarak, bunu AppDelegate'imde yapmak istiyorum:

// url request & response work fine, assume success is a BOOL here
// that indicates whether login was successful or not

if (success) {
          // 'push' main view controller
} else {
          // 'push' login view controller
}

PerformSegueWithIdentifier yöntemini biliyorum: ancak bu yöntem UIViewController'ın bir örnek yöntemidir, bu nedenle AppDelegate içinden çağrılamaz. Bunu mevcut film şeridimi kullanarak nasıl yaparım?

DÜZENLE:

Storyboard'un ilk görünüm denetleyicisi artık hiçbir şeye bağlı olmayan bir gezinme denetleyicisidir. SetRootViewController: ayrımını kullandım çünkü MainIdentifier bir UITabBarController. O zaman repliklerim şöyle görünüyor:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    BOOL isLoggedIn = ...;    // got from server response

    NSString *segueId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
    UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:segueId];

    if (isLoggedIn) {
        [self.window setRootViewController:initViewController];
    } else {
        [(UINavigationController *)self.window.rootViewController pushViewController:initViewController animated:NO];
    }

    return YES;
}

Önerilere / iyileştirmelere açığız!

Yanıtlar:


25

Film şeridinizin "ana film şeridi" ( UIMainStoryboardFileInfo.plist'inizdeki anahtar ) olarak ayarlandığını varsayıyorum . Bu durumda, UIKit, film şeridini yükleyecek ve göndermeden önce ilk görünüm denetleyicisini pencerenizin kök görünüm denetleyicisi olarak ayarlayacaktır.application:didFinishLaunchingWithOptions: AppDelegate'inize ayarlayacaktır.

Ayrıca, film şeridinizdeki ilk görünüm denetleyicisinin, ana veya oturum açma görünüm denetleyicinizi üzerine itmek istediğiniz gezinme denetleyicisi olduğunu da varsayıyorum.

Pencerenizden kök görünüm denetleyicisini isteyebilir ve performSegueWithIdentifier:sender:mesajı ona gönderebilirsiniz :

NSString *segueId = success ? @"pushMain" : @"pushLogin";
[self.window.rootViewController performSegueWithIdentifier:segueId sender:self];

1
Kod satırlarınızı uygulamamda uyguladım: didFinishLaunchingWithOptions: method. Hata ayıklama, rootViewController'ın aslında ilk gezinme denetleyicisi olduğunu, ancak segmentin gerçekleştirilmediğini gösterir (gezinme çubuğu gösteriliyor, geri kalanı siyah). İlk gezinti denetleyicisinin artık bir rootViewController'a sahip olmadığını söylemeliyim, sadece 2 segment (StartLoginSegue ve StartMainSegue).
mmvie

3
Evet, benim için de çalışmıyor. Sizin için işe yaramıyorsa neden Yanıtlandı olarak işaretlediniz?
daidai

3
Bunun doğru yanıt olduğuna inanıyorum. 1. uygulama temsilcinizde bir pencere özelliğine sahip olmanız ve 2. [[self window] makeKeyAndVisible]uygulamada arama yapmanız gerekir: didFinishLaunchingWithOptions: koşullu segmentleri denemeden ve gerçekleştirmeden önce. UIApplicationMain () 'in makeKeyAndVisible' a mesaj göndermesi varsayılır, ancak bunu sadece didFinish ... Options: finishes'den sonra yapar. Ayrıntılar için Apple belgelerinde "Görüntü Denetleyicileri Arasındaki Koordinasyon Çalışmaları" konusuna bakın.
edelaney05

Bu doğru fikir, ancak pek işe yaramıyor. Çalışan bir çözüm için cevabımı görün.
Matthew Frederick

@MatthewFrederick Çözümünüz, ilk denetleyici bir gezinme denetleyicisi ise işe yarayacaktır, ancak düz görüntü denetleyicisi değilse işe yarayacaktır. Gerçek yanıt, yalnızca pencere ve kök görünüm denetleyicisini kendiniz oluşturmaktır - aslında Apple'ın Görünüm Denetleyici Programlama Kılavuzu'nda önerdiği şey budur. Ayrıntılar için aşağıdaki cevabıma bakın.
followben

170

Burada önerilen bazı çözümlere şaşırdım.

Görsel senaryo taslağınızda, görünümleri gizleyen ve viewDidAppear'daki bölümleri ateşleyen kukla gezinme denetleyicilerine veya diğer saldırılara gerçekten gerek yoktur.

Plist dosyanızda film şeridi yapılandırılmadıysa, hem pencereyi hem de kök görünüm denetleyicisini kendiniz oluşturmanız gerekir :

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    BOOL isLoggedIn = ...;    // from your server response

    NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard" bundle:nil];
    UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:storyboardId];

    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.window.rootViewController = initViewController;
    [self.window makeKeyAndVisible];

    return YES;
}

Film şeridi ise didFinishLaunching: denir ve makeKeyAndVisible sizin için pencere çağrılır uygulamanın plist yapılandırılmış, pencere ve kök görünümü denetleyicisi zaten zaman uygulama tarafından kurulacaktır.

Bu durumda, daha da basit:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{        
    BOOL isLoggedIn = ...;    // from your server response

    NSString *storyboardId = isLoggedIn ? @"MainIdentifier" : @"LoginIdentifier";
    self.window.rootViewController = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:storyboardId];

    return YES;
}

@AdamRabung Spot açık - OP'nin değişken adlarını kopyaladım, ancak yanıtımı netlik için güncelledim. Şerefe.
followben

film şeridi durumu için: Kök görünüm denetleyiciniz olarak UINavigationViewcontroller kullanıyorsanız, sonraki görünüm denetleyicisine basmanız gerekir.
Shirish Kumar

Bu benim için karmaşık hiyerarşi gezinti denetleyicisinden daha sezgisel bir yol. Bunu seviyorum
Elliot Yap

Merhaba @followben, uygulamamda, storyBoard'da rootViewController'im var, onun bir tabBarController'ı ve tabBar ile ilişkili tüm VC'ler de VC'de tasarlandı, bu yüzden şimdi uygulamamın adım adım açıklamasını yapmak istediğim bir vakam var. şimdi uygulamam ilk başlatıldığında, tabBarcontroller yerine kök VC olarak adım adım VC yapmak istiyorum ve izlenecek yolum bittiğinde, tabBarController'ı rootViewController olarak yapmak istiyorum. Nasıl yapacağımı anlamıyorum
Ranjit

1
Sunucuya yapılan istek eşzamansızsa ne olur?
Lior Burg

18

Film şeridinizin giriş noktası bir UINavigationController:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {


    //Your View Controller Identifiers defined in Interface Builder
    NSString *firstViewControllerIdentifier  = @"LoginViewController";
    NSString *secondViewControllerIdentifier = @"MainMenuViewController";

    //check if the key exists and its value
    BOOL appHasLaunchedOnce = [[NSUserDefaults standardUserDefaults] boolForKey:@"appHasLaunchedOnce"];

    //if the key doesn't exist or its value is NO
    if (!appHasLaunchedOnce) {
        //set its value to YES
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"appHasLaunchedOnce"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }

    //check which view controller identifier should be used
    NSString *viewControllerIdentifier = appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;

    //IF THE STORYBOARD EXISTS IN YOUR INFO.PLIST FILE AND YOU USE A SINGLE STORYBOARD
    UIStoryboard *storyboard = self.window.rootViewController.storyboard;

    //IF THE STORYBOARD DOESN'T EXIST IN YOUR INFO.PLIST FILE OR IF YOU USE MULTIPLE STORYBOARDS
    //UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"YOUR_STORYBOARD_FILE_NAME" bundle:nil];

    //instantiate the view controller
    UIViewController *presentedViewController = [storyboard instantiateViewControllerWithIdentifier:viewControllerIdentifier];

    //IF YOU DON'T USE A NAVIGATION CONTROLLER:
    [self.window setRootViewController:presentedViewController];

    return YES;
}

Film şeridinizin giriş noktası bir UINavigationControllerdeğişim ise:

//IF YOU DON'T USE A NAVIGATION CONTROLLER:
[self.window setRootViewController:presentedViewController];

ile:

//IF YOU USE A NAVIGATION CONTROLLER AS THE ENTRY POINT IN YOUR STORYBOARD:
UINavigationController *navController = (UINavigationController *)self.window.rootViewController;
[navController pushViewController:presentedViewController animated:NO];

1
İyi çalıştı. Sadece bir yorum, bu "firstViewControllerIdentifier" ı yalnızca başlangıçta girdikten sonra göstermiyor mu? Öyleyse tersine çevrilmesi gerekmez mi? appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;
ammianus

@ammianus haklısın. Tersine çevrilmeli ve ben düzenlenmeli.
Razvan 08

9

AppDelegate'inizin application:didFinishLaunchingWithOptionsyönteminde return YESsatırdan önce şunu ekleyin:

UINavigationController *navigationController = (UINavigationController*) self.window.rootViewController;
YourStartingViewController *yourStartingViewController = [[navigationController viewControllers] objectAtIndex:0];
[yourStartingViewController performSegueWithIdentifier:@"YourSegueIdentifier" sender:self];

YourStartingViewControllerGerçek ilk görünüm denetleyici sınıfınızın adıyla değiştirin (mutlaka görünmesini istemediğiniz) veYourSegueIdentifier segue gerçek adıyla arasındaki denetleyici ve gerçekte (segue ardına başlamak istiyorum birini başlayan ).

ifHer zaman olmasını istemiyorsanız, bu kodu bir koşullu olarak sarın .


6

Zaten bir Öykü Panosu kullandığınızı göz önünde bulundurarak, bunu kullanıcıya özel bir denetleyici olan MyViewController'ı sunmak için kullanabilirsiniz ( followben'in yanıtını biraz azaltın ).

In AppDelegate.m :

-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    MyCustomViewController *controller = [self.window.rootViewController.storyboard instantiateViewControllerWithIdentifier:@"MyCustomViewController"];

    // now configure the controller with a model, etc.

    self.window.rootViewController = controller;

    return YES;
}

İnstantiateViewControllerWithIdentifier'a iletilen dize, arayüz oluşturucuda ayarlanabilen Storyboard ID'yi ifade eder:

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

Bunu gerektiği gibi mantığa sarın.

Bir UINavigationController ile başlıyorsanız, bu yaklaşım size gezinme kontrolleri vermeyecektir.

Arayüz oluşturucu aracılığıyla ayarlanan bir gezinme denetleyicisinin başlangıç ​​noktasından 'ileri atlamak' için şu yaklaşımı kullanın:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UINavigationController *navigation = (UINavigationController *) self.window.rootViewController;

    [navigation.visibleViewController performSegueWithIdentifier:@"my-named-segue" sender:nil];

    return YES;
}

4

Neden ilk görünen oturum açma ekranına sahip değilsiniz, kullanıcının zaten oturum açmış olup olmadığını kontrol edin ve hemen bir sonraki ekrana gidin? Hepsi ViewDidLoad'da.


2
Bu gerçekten işe yarıyor, ancak hedeflerim, uygulama hala sunucu yanıtını beklediği sürece (giriş başarılı olsun ya da olmasın) başlatma görüntüsünü göstermektir. Tıpkı Facebook uygulaması gibi ...
mmvie

2
Her zaman ilk görünümünüze sahip olabilirsiniz, sadece açılışınız ile aynı görüntüyü kullanan bir UIImage ve arka planda oturum açıp açmadığınızı kontrol edip sonraki görünümü görüntüleyebilirsiniz.
Darren

3

Aynı hızlı uygulama:

UINavigationControllerFilm şeridinde giriş noktası olarak kullanıyorsanız

let storyboard = UIStoryboard(name: "Main", bundle: nil)

var rootViewController = self.window!.rootViewController as! UINavigationController;

    if(loginCondition == true){

         let profileController = storyboard.instantiateViewControllerWithIdentifier("ProfileController") as? ProfileController  
         rootViewController.pushViewController(profileController!, animated: true) 
    }
    else {

         let loginController =   storyboard.instantiateViewControllerWithIdentifier("LoginController") as? LoginController 
         rootViewController.pushViewController(loginController!, animated: true) 
    }

1

Bu, iOS7'de çalışan çözümdür. İlk yüklemeyi hızlandırmak ve gereksiz yükleme yapmamak için, Storyboard dosyamda "DUMMY" adında tamamen boş bir UIViewcontroller var. O zaman şu kodu kullanabilirim:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UIStoryboard* storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];

    NSString* controllerId = @"Publications";
    if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasSeenIntroduction"])
    {
        controllerId = @"Introduction";
    }
    else if (![NSUserDefaults.standardUserDefaults boolForKey:@"hasDonePersonalizationOrLogin"])
    {
        controllerId = @"PersonalizeIntro";
    }

    if ([AppDelegate isLuc])
    {
        controllerId = @"LoginStart";
    }

    if ([AppDelegate isBart] || [AppDelegate isBartiPhone4])
    {
        controllerId = @"Publications";
    }

    UIViewController* controller = [storyboard instantiateViewControllerWithIdentifier:controllerId];
    self.window.rootViewController = controller;

    return YES;
}

0

Gezinme Denetleyicisinin Kök Görünüm Denetleyicisi olan yeni bir MainViewController oluşturmanızı öneririm. Bunu yapmak için, kontrolü basılı tutun, ardından Navigasyon Denetleyicisi ile MainViewController arasındaki bağlantıyı sürükleyin, komut isteminden 'İlişki - Kök Görünüm Denetleyicisi'ni seçin.

MainViewController'da:

- (void)viewDidLoad
{
    [super viewDidLoad];
    if (isLoggedIn) {
        [self performSegueWithIdentifier:@"HomeSegue" sender:nil];
    } else {
        [self performSegueWithIdentifier:@"LoginSegue" sender:nil];
    }
}

Ana Sayfa ve Oturum Açma görünüm denetleyicileri ile MainViewController arasında segmentler oluşturmayı unutmayın. Bu yardımcı olur umarım. :)


0

Birçok farklı yöntemi denedikten sonra bu sorunu şununla çözebildim:

-(void)viewWillAppear:(BOOL)animated {

    // Check if user is already logged in
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    if ([[prefs objectForKey:@"log"] intValue] == 1) {
        self.view.hidden = YES;
    }
}

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

    // Check if user is already logged in
    NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
    if ([[prefs objectForKey:@"log"] intValue] == 1) {
        [self performSegueWithIdentifier:@"homeSeg3" sender:self];
    }
}

-(void)viewDidUnload {
    self.view.hidden = NO;
}

Taylor'da çok uzak değilseniz, daha basit bir şeye yeniden düzenleme yapmak isteyebilirsiniz. Ayrıntılar için
cevabıma
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.