[objective-c] AppDelegate에서 스토리 보드의 다른 위치에서 조건부로 시작

작업 로그인 및 기본보기 컨트롤러로 설정된 스토리 보드가 있으며, 후자는 로그인이 성공할 때 사용자가 탐색하는보기 컨트롤러입니다. 내 목표는 인증 (키 체인에 저장 됨)이 성공하면 즉시 메인 뷰 컨트롤러를 표시하고 인증이 실패하면 로그인 뷰 컨트롤러를 표시하는 것입니다. 기본적으로 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 내에서 호출 할 수 없다. 기존 스토리 보드를 사용하여이 작업을 수행하려면 어떻게합니까?

편집하다:

Storyboard의 초기보기 컨트롤러는 이제 아무것도 연결되지 않은 탐색 컨트롤러입니다. MainIdentifier가 UITabBarController이기 때문에 setRootViewController : 구분을 사용했습니다. 그러면 내 라인은 다음과 같습니다.

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

제안 / 개선을 환영합니다!



답변

스토리 보드가 “기본 스토리 보드”( UIMainStoryboardFileInfo.plist의 키)로 설정되어 있다고 가정합니다 . 이 경우 UIKit은 스토리 보드를로드하고 application:didFinishLaunchingWithOptions:AppDelegate로 보내기 전에 초기보기 컨트롤러를 창의 루트보기 컨트롤러 로 설정합니다.

또한 스토리 보드의 초기보기 컨트롤러가 기본 또는 로그인보기 컨트롤러를 푸시하려는 탐색 컨트롤러라고 가정합니다.

창에 루트 뷰 컨트롤러를 요청하고 performSegueWithIdentifier:sender:메시지를 보낼 수 있습니다.

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


답변

여기에서 제안 된 몇 가지 솔루션에 놀랐습니다.

스토리 보드에 더미 탐색 컨트롤러가 필요하지 않고 viewDidAppear에서 뷰를 숨기고 segue를 실행하거나 다른 해킹을 할 필요가 없습니다.

plist 파일에 스토리 보드를 구성하지 않은 경우 창과 루트 뷰 컨트롤러를 직접 만들어야합니다 .

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

스토리 보드 앱의 plist에 구성되어있는 경우 application : didFinishLaunching :이 호출 될 때 창과 루트 뷰 컨트롤러가 이미 설정되어 있고 makeKeyAndVisible이 창에서 호출됩니다.

이 경우 더 간단합니다.

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


답변

스토리 보드의 진입 점이 다음이 아닌 경우 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];


답변

AppDelegate의 application:didFinishLaunchingWithOptions메서드에서 return YES줄 앞에 다음을 추가합니다.

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

교체 YourStartingViewController실제 첫 번째 뷰 컨트롤러 클래스 (당신이 반드시 표시하지 않는 한)의 이름과 YourSegueIdentifierSEGUE의 실제 이름 사이의 컨트롤러와 실제로합니다 (SEGUE 후 하나에 시작하려는 일을 시작 ).

if항상 발생하는 것을 원하지 않는 경우 해당 코드를 조건부로 래핑하십시오 .


답변

이미 스토리 보드를 사용하고 있음을 감안할 때, 당신은 MyViewController, 사용자 정의 컨트롤러 (끓는 아래로 사용자에게 제공하기 위해 이것을 사용할 수 있습니다 followben의 대답은 조금).

에서 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에 전달 된 문자열은 인터페이스 빌더에서 설정할 수있는 Storyboard ID를 참조합니다.

여기에 이미지 설명 입력

필요에 따라 이것을 논리로 감싸십시오.

하지만 UINavigationController로 시작하는 경우이 접근 방식은 탐색 컨트롤을 제공하지 않습니다.

인터페이스 빌더를 통해 설정 한 탐색 컨트롤러의 시작점에서 ‘앞으로 점프’하려면 다음 접근 방식을 사용하십시오.

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

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

    return YES;
}


답변

먼저 나타나는 로그인 화면이 나오지 않는 이유는 사용자가 이미 로그인되어 있는지 확인하고 바로 다음 화면을 푸시하는 것입니다. 모두 ViewDidLoad에 있습니다.


답변

동일한 신속한 구현 :

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)
    }