AppDelegate से स्टोरीबोर्ड में अलग-अलग स्थानों पर सशर्त रूप से प्रारंभ करें


107

मेरे पास काम करने वाले लॉगिन और मुख्य दृश्य नियंत्रक के साथ स्थापित एक स्टोरीबोर्ड है, बाद वाला व्यू कंट्रोलर है जिसमें लॉगिन सफल होने पर उपयोगकर्ता को नेविगेट किया जाता है। मेरा उद्देश्य मुख्य दृश्य नियंत्रक को तुरंत दिखाना है अगर प्रमाणीकरण (कीचेन में संग्रहीत) सफल है, और प्रमाणीकरण विफल होने पर लॉगिन दृश्य नियंत्रक दिखा। मूल रूप से, मैं अपने AppDelegate में यह करना चाहता हूं:

// 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 के बारे में जानता हूं: लेकिन यह विधि UIViewController की एक उदाहरण विधि है, इसलिए AppDelegate के भीतर से कॉल करने योग्य नहीं है। मैं अपने मौजूदा स्टोरीबोर्ड का उपयोग कैसे करूँ ??

संपादित करें:

स्टोरीबोर्ड का प्रारंभिक दृश्य नियंत्रक अब एक नेविगेशन नियंत्रक है जो किसी भी चीज़ से जुड़ा नहीं है। मैंने setRootViewController का उपयोग किया: भेद क्योंकि MainIdentifier एक UITabBarController है। तो फिर यह मेरी लाइनें कैसी दिखती हैं:

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

सुझाव / सुधार का स्वागत है!

जवाबों:


25

मुझे लगता है कि आपका स्टोरीबोर्ड "मुख्य स्टोरीबोर्ड" ( UIMainStoryboardFileआपके Info.plist में कुंजी ) के रूप में सेट है । उस स्थिति में, UIKit स्टोरीबोर्ड को लोड करेगा और भेजे जाने से पहले आपकी विंडो के रूट व्यू कंट्रोलर के रूप में इसका प्रारंभिक व्यू कंट्रोलर सेट करेगाapplication:didFinishLaunchingWithOptions: के रूप में आपके AppDelegate को से ।

मैं यह भी मानता हूं कि आपके स्टोरीबोर्ड में प्रारंभिक दृश्य नियंत्रक नेविगेशन नियंत्रक है, जिस पर आप अपने मुख्य या लॉगिन दृश्य नियंत्रक को धक्का देना चाहते हैं।

आप अपने विंडो को उसके रूट व्यू कंट्रोलर से पूछ सकते हैं, और उसे performSegueWithIdentifier:sender:संदेश भेज सकते हैं:

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

1
मैंने अपने कोड की अपनी पंक्तियों को अपने आवेदन में लागू किया: doFinishLaunchingWithOptions: विधि। डिबगिंग से पता चलता है कि rootViewController वास्तव में प्रारंभिक नेविगेशन कंट्रोलर है, हालांकि सेग को प्रदर्शन नहीं किया जाता है (नेविगेशन बार दिखा रहा है, बाकी काला है)। मुझे कहना होगा कि शुरुआती नेविगेशन कंट्रोलर के पास अब कोई rootViewController नहीं है, केवल 2 सेगमेंट (StartLoginSegue और StartMainSegue) हैं।
mmvie

3
हां, मेरे लिए भी काम नहीं कर रहा। अगर आपने यह आपके लिए काम नहीं किया तो आपने इसका उत्तर क्यों दिया?
दिदई

3
मेरा मानना ​​है कि यह सही उत्तर है। आपको अपने ऐप प्रतिनिधि पर एक विंडो प्रॉपर्टी की आवश्यकता है और 2. एप्लिकेशन [[self window] makeKeyAndVisible]में कॉल करें : didFinishLaunchingWithOptions: इससे पहले कि आप कोशिश करें और सशर्त सेगमेंट करें। UIApplicationMain () को मेकएंडएविजिबल संदेश देने के लिए माना जाता है, लेकिन ऐसा करने के बाद ही करता है ... विकल्प: खत्म। विवरण के लिए Apple डॉक्स में "व्यू कंट्रोलर्स के बीच समन्वय प्रयास" देखें।
edelaney05

यह सही विचार है, लेकिन काफी काम नहीं करता है। एक काम के समाधान के लिए मेरा जवाब देखें।
मैथ्यू फ्रेडरिक

@MatthewFrederick आपका समाधान काम करेगा यदि प्रारंभिक नियंत्रक एक नेविगेशन नियंत्रक है, लेकिन ऐसा नहीं है यदि यह एक सादा दृश्य नियंत्रक है। असली जवाब सिर्फ खिड़की और रूट व्यू कंट्रोलर बनाने के लिए है - वास्तव में यह वही है जो Apple व्यू कंट्रोलर प्रोग्रामिंग गाइड में सुझाता है। विवरण के लिए नीचे मेरा उत्तर देखें।
अनुगमन करें

170

मैं यहां सुझाए जा रहे कुछ समाधानों पर आश्चर्यचकित हूं।

आपके स्टोरीबोर्ड में डमी नेविगेशन नियंत्रकों के लिए वास्तव में कोई ज़रूरत नहीं है, दृश्यदर्शी पर दृश्य और फायरिंग सेगमेंट को छिपाते हुए: या किसी अन्य हैक।

यदि आपके पास स्टोरीबोर्ड आपकी प्लिस्ट फ़ाइल में कॉन्फ़िगर नहीं है, तो आपको विंडो और रूट व्यू कंट्रोलर दोनों स्वयं बनाने होंगे :

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

अगर स्टोरीबोर्ड है ऐप के प्लिस्ट में कॉन्फ़िगर किया गया है, तो विंडो और रूट व्यू कंट्रोलर को पहले से ही समय एप्लिकेशन द्वारा सेटअप किया जाएगा: didFishishLaunching: कहा जाता है, और makeKeyAndVouble आपके लिए विंडो पर कॉल किया जाएगा।

उस मामले में, यह और भी सरल है:

- (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 स्पॉट ऑन - मैंने अभी ओपी के चर नामों की नकल की है, लेकिन मैंने स्पष्टता के लिए अपना जवाब अपडेट कर दिया है। चीयर्स।
अनुगमन तिथि

स्टोरीबोर्ड मामले के लिए: यदि आप अपने रूट व्यू कंट्रोलर के रूप में यूनेविविव्यू व्यू कॉन्ट्रोलर का उपयोग कर रहे हैं तो आपको अगले व्यू कंट्रोलर को धक्का देना होगा।
शिरीष कुमार

यह जटिल जटिल पदानुक्रम नेविगेशन नियंत्रक के बजाय मेरे लिए अधिक सहज तरीका है। इसे प्यार करें
इलियट याप

नमस्कार @followben, मेरे ऐप में, मेरे पास अपना रूट-व्यू-कंट्रोलर है स्टोरीबोर्ड में, इसका एक टैब-कॉन्ट्रोलर, और टैबबेर के साथ जुड़े सभी वीसी भी वीसी में डिज़ाइन किए गए हैं, इसलिए अब मेरे पास एक मामला है, जहां मैं अपने ऐप का वॉकथ्रू दिखाना चाहता हूं, इसलिए अब जब मेरा ऐप पहली बार लॉन्च हुआ है, तो मैं tabBarcontroller के बजाय root VC को रूट VC बनाना चाहता हूं और जब मेरा walkthrough खत्म हो जाता है, तो मैं tabBarController को rootViewController के रूप में बनाना चाहता हूं। इसे मैं कैसे समझ नहीं पा रहा हूँ
रंजीत

1
यदि सर्वर से अनुरोध अतुल्यकालिक है तो क्या होगा?
बर्ग

18

यदि आपके स्टोरीबोर्ड का प्रवेश बिंदु a नहीं है 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;
}

यदि आपके स्टोरीबोर्ड का प्रवेश बिंदु एक UINavigationControllerप्रतिस्थापन है:

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

साथ में:

//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
अच्छा काम किए। केवल एक टिप्पणी, यह "firstViewControllerIdentifier" शो शुरू होने के बाद ही प्रदर्शित नहीं करता है? तो क्या इसका उल्टा नहीं होना चाहिए? appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;
19

@ स्तनधारी आप सही हैं। उन्हें उलट दिया जाना चाहिए और मैंने संपादित किया।
राज़्वान

9

अपने AppDelegate की application:didFinishLaunchingWithOptionsविधि में, return YESलाइन से पहले , जोड़ें:

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

YourStartingViewControllerअपने वास्तविक प्रथम दृश्य नियंत्रक वर्ग के नाम से बदलें (जिसे आप आवश्यक रूप से प्रकट नहीं करना चाहते हैं) औरYourSegueIdentifier उस शुरुआती नियंत्रक के बीच सेग के वास्तविक नाम के साथ और जिसे आप वास्तव में शुरू करना चाहते हैं (सेग के बाद एक) )।

उस कोड को एक ifसशर्त में लपेटें यदि आप हमेशा ऐसा नहीं चाहते हैं।


6

यह देखते हुए कि आप पहले से ही स्टोरीबोर्ड का उपयोग कर रहे हैं, आप इसका उपयोग उपयोगकर्ता को MyViewController, एक कस्टम कंट्रोलर ( फॉलोइंग के उत्तर को थोड़ा सा बढ़ाकर ) प्रस्तुत करने के लिए कर सकते हैं ।

में 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;
}

InstantiateViewControllerWithIdentifier को दिया गया स्ट्रिंग स्टोरीबोर्ड आईडी को संदर्भित करता है, जिसे इंटरफ़ेस बिल्डर में सेट किया जा सकता है:

यहां छवि विवरण दर्ज करें

आवश्यकतानुसार इसे केवल तर्क में लपेटें।

यदि आप एक UINavigationController के साथ शुरू कर रहे हैं, हालांकि, यह दृष्टिकोण आपको नेविगेशन नियंत्रण नहीं देगा।

इंटरफ़ेस बिल्डर के माध्यम से स्थापित एक नेविगेशन नियंत्रक के शुरुआती बिंदु से 'आगे कूदने' के लिए, इस दृष्टिकोण का उपयोग करें:

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

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

    return YES;
}

4

क्यों नहीं लॉगिन स्क्रीन जो पहले दिखाई देती है, जांचें कि क्या उपयोगकर्ता पहले से लॉग इन है और अगली स्क्रीन को सीधे हटा दें? ViewDidLoad में सभी।


2
यह वास्तव में काम करता है, लेकिन मेरा लक्ष्य लॉन्च की छवि दिखाना है जब तक कि ऐप अभी भी सर्वर की प्रतिक्रिया का इंतजार कर रहा है (लॉगिन सफल था या नहीं)। फेसबुक ऐप की तरह ही ...
mmvie

2
आपके पास हमेशा अपना पहला दृश्य हो सकता है सिर्फ UIImage जो आपके छप के रूप में एक ही छवि का उपयोग करता है और यह देखने के लिए पृष्ठभूमि की जांच करें कि क्या लॉग इन किया गया है और अगला दृश्य प्रदर्शित करता है।
डैरेन

3

उसी का स्विफ्ट कार्यान्वयन:

यदि आप UINavigationControllerस्टोरीबोर्ड में प्रवेश बिंदु के रूप में उपयोग करते हैं

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

यह समाधान है जो n iOS7 काम करता है। प्रारंभिक लोडिंग में तेजी लाने के लिए और कोई भी अनावश्यक लोडिंग नहीं करने के लिए, मेरी स्टोरीबोर्ड फ़ाइल में "DUMMY" नामक एक पूरी तरह से खाली UIViewcontroller है। फिर मैं निम्नलिखित कोड का उपयोग कर सकता हूं:

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

मैं एक नया MainViewController बनाने का सुझाव देता हूं जो कि नेविगेशन कंट्रोलर का रूट व्यू कंट्रोलर है। ऐसा करने के लिए, बस नियंत्रण रखें, फिर नेविगेशन नियंत्रक और MainViewController के बीच कनेक्शन खींचें, शीघ्रता से 'संबंध - रूट व्यू नियंत्रक' चुनें।

MainViewController में:

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

होम और लॉगिन व्यू कंट्रोलर्स के साथ MainViewController के बीच सेगमेंट बनाना याद रखें। उम्मीद है की यह मदद करेगा। :)


0

कई अलग-अलग तरीकों की कोशिश करने के बाद, मैं इस समस्या को हल करने में सक्षम था:

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

यदि आप टेलर के साथ बहुत दूर नहीं हैं, तो आप कुछ सरल करना चाहते हैं। विवरण के लिए मेरा उत्तर देखें :)
Follow '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.