Bắt đầu có điều kiện ở các vị trí khác nhau trong bảng phân cảnh từ AppDelegate


107

Tôi có một bảng phân cảnh được thiết lập với đăng nhập đang hoạt động và bộ điều khiển chế độ xem chính, bảng sau là bộ điều khiển chế độ xem mà người dùng được điều hướng đến khi đăng nhập thành công. Mục tiêu của tôi là hiển thị bộ điều khiển chế độ xem chính ngay lập tức nếu xác thực (được lưu trữ trong chuỗi khóa) thành công và hiển thị bộ điều khiển chế độ xem đăng nhập nếu xác thực không thành công. Về cơ bản, tôi muốn thực hiện việc này trong AppDelegate của mình:

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

Tôi biết về phương thức performanceSegueWithIdentifier: nhưng phương thức này là một phương thức thể hiện của UIViewController, vì vậy không thể gọi được từ bên trong AppDelegate. Làm cách nào để thực hiện việc này bằng cách sử dụng bảng phân cảnh hiện có của tôi ??

BIÊN TẬP:

Bộ điều khiển chế độ xem ban đầu của Storyboard hiện là bộ điều khiển điều hướng không được kết nối với bất kỳ thứ gì. Tôi đã sử dụng setRootViewController: phân biệt vì MainIdentifier là một UITabBarController. Sau đó, đây là những gì các dòng của tôi trông như thế này:

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

Đề xuất / cải tiến được hoan nghênh!

Câu trả lời:


25

Tôi cho rằng bảng phân cảnh của bạn được đặt làm "bảng phân cảnh chính" (chìa khóa UIMainStoryboardFiletrong Info.plist của bạn). Trong trường hợp đó, UIKit sẽ tải bảng phân cảnh và đặt bộ điều khiển chế độ xem ban đầu làm bộ điều khiển chế độ xem gốc của cửa sổ trước khi nó gửi application:didFinishLaunchingWithOptions:tới AppDelegate của bạn.

Tôi cũng giả định rằng bộ điều khiển chế độ xem ban đầu trong bảng phân cảnh của bạn là bộ điều khiển điều hướng mà bạn muốn đẩy bộ điều khiển chế độ xem chính hoặc đăng nhập của mình lên.

Bạn có thể yêu cầu cửa sổ của mình cung cấp bộ điều khiển chế độ xem gốc của nó và gửi performSegueWithIdentifier:sender:thông báo đến nó:

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

1
Tôi đã triển khai các dòng mã của bạn trong ứng dụng của tôi: phương thức didFinishLaunchingWithOptions:. Gỡ lỗi cho thấy rootViewController thực sự là bộ điều khiển điều hướng ban đầu, tuy nhiên, segue không được thực hiện (thanh điều hướng đang hiển thị, phần còn lại là màu đen). Tôi phải nói rằng bộ điều khiển điều hướng ban đầu không có rootViewController nữa, chỉ có 2 segues (StartLoginSegue và StartMainSegue).
mmvie

3
Đúng, cũng không làm việc cho tôi. Tại sao bạn đánh dấu nó Đã trả lời nếu nó không hiệu quả với bạn?
daidai

3
Tôi tin rằng đây là câu trả lời chính xác. Bạn cần 1. có thuộc tính cửa sổ trên đại biểu ứng dụng của bạn và 2. gọi [[self window] makeKeyAndVisible]trong ứng dụng: didFinishLaunchingWithOptions: trước khi bạn thử và thực hiện các segues có điều kiện. UIApplicationMain () được cho là thông báo makeKeyAndVible nhưng chỉ thực hiện sau didFinish ... Options: kết thúc. Tìm "Nỗ lực phối hợp giữa các bộ điều khiển chế độ xem" trong tài liệu của Apple để biết chi tiết.
edelaney05

Đây là ý tưởng đúng, nhưng không hoàn toàn hiệu quả. Xem câu trả lời của tôi cho một giải pháp làm việc.
Matthew Frederick

@MatthewFrederick Giải pháp của bạn sẽ hoạt động nếu bộ điều khiển ban đầu là bộ điều khiển điều hướng, nhưng không hoạt động nếu đó là bộ điều khiển chế độ xem đơn giản. Câu trả lời thực sự chỉ là tự tạo cửa sổ và bộ điều khiển chế độ xem gốc - thực sự đây là những gì Apple đề xuất trong Hướng dẫn lập trình bộ điều khiển chế độ xem. Xem câu trả lời của tôi bên dưới để biết chi tiết.
followben

170

Tôi ngạc nhiên về một số giải pháp được đề xuất ở đây.

Thực sự không cần bộ điều khiển điều hướng giả trong bảng phân cảnh của bạn, ẩn các chế độ xem và kích hoạt các segues trên viewDidAppear: hoặc bất kỳ thủ thuật nào khác.

Nếu bạn chưa định cấu hình bảng phân cảnh trong tệp plist của mình, bạn phải tự tạo cả cửa sổ và bộ điều khiển chế độ xem gốc :

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

Nếu bảng phân cảnh được định cấu hình trong plist của ứng dụng, bộ điều khiển chế độ xem cửa sổ và gốc sẽ được ứng dụng thời gian thiết lập: didFinishLaunching: được gọi và makeKeyAndVible sẽ được gọi trên cửa sổ cho bạn.

Trong trường hợp đó, nó thậm chí còn đơn giản hơn:

- (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 Điểm trên - Tôi vừa sao chép tên biến của OP, nhưng tôi đã cập nhật câu trả lời của mình cho rõ ràng. Chúc mừng.
followben

đối với trường hợp bảng phân cảnh: Nếu bạn đang sử dụng UINavigationViewcontroller làm bộ điều khiển chế độ xem gốc thì bạn sẽ cần đẩy bộ điều khiển chế độ xem tiếp theo.
Shirish Kumar,

Đây là cách trực quan hơn đối với tôi thay vì đi qua bộ điều khiển điều hướng phân cấp phức tạp. Yêu cái này
Elliot Yap

Xin chào @followben, trong ứng dụng của tôi, tôi có rootViewController trong storyBoard, tabBarController của nó và tất cả các VC được liên kết với tabBar cũng được thiết kế trong VC, vì vậy bây giờ tôi có một trường hợp, nơi tôi muốn hiển thị hướng dẫn ứng dụng của mình, Vì vậy bây giờ khi ứng dụng của tôi lần đầu tiên được khởi chạy, tôi muốn đặt walkthrough VC làm VC gốc thay vì tabBarcontroller và khi chương trình walkthrough của tôi kết thúc, tôi muốn đặt tabBarController làm rootViewController. Làm thế nào để làm điều đó tôi không hiểu biết
Ranjit

1
Điều gì sẽ xảy ra nếu yêu cầu tới máy chủ không đồng bộ?
Lior Burg

18

NẾU điểm vào bảng phân cảnh của bạn không phải là 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;
}

NẾU điểm vào bảng phân cảnh của bạn LÀ điểm UINavigationControllerthay thế:

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

với:

//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
Làm việc tốt. Chỉ là một nhận xét, điều này không hiển thị "firstViewControllerIdentifier" chỉ sau khi họ đã nhập ban đầu? Vì vậy, nó không nên được đảo ngược? appHasLaunchedOnce ? secondViewControllerIdentifier : firstViewControllerIdentifier;
ammianus

@ammianus bạn nói đúng. Chúng nên được đảo ngược và tôi đã chỉnh sửa.
Razvan

9

Trong application:didFinishLaunchingWithOptionsphương thức AppDelegate của bạn , trước return YESdòng, hãy thêm:

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

Thay thế YourStartingViewControllerbằng tên của lớp bộ điều khiển chế độ xem đầu tiên thực tế của bạn (lớp mà bạn không muốn nhất thiết phải xuất hiện) và YourSegueIdentifierbằng tên thực tế của bộ điều khiển giữa bộ điều khiển bắt đầu đó và bộ điều khiển bạn muốn thực sự bắt đầu (lớp sau bộ điều khiển ).

Hãy bọc mã đó trong một ifđiều kiện nếu bạn không muốn nó luôn xảy ra.


6

Giả sử bạn đã sử dụng Storyboard, bạn có thể sử dụng nó để giới thiệu cho người dùng MyViewController, một bộ điều khiển tùy chỉnh ( Tóm tắt câu trả lời của followben một chút).

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

Chuỗi được chuyển đến InstantiateViewControllerWithIdentifier đề cập đến ID bảng phân cảnh, có thể được đặt trong trình tạo giao diện:

nhập mô tả hình ảnh ở đây

Chỉ cần gói điều này trong logic khi cần thiết.

Tuy nhiên, nếu bạn đang bắt đầu với UINavigationController, cách tiếp cận này sẽ không cung cấp cho bạn các điều khiển điều hướng.

Để 'nhảy về phía trước' từ điểm bắt đầu của bộ điều khiển điều hướng được thiết lập thông qua trình tạo giao diện, hãy sử dụng phương pháp này:

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

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

    return YES;
}

4

Tại sao màn hình đăng nhập không xuất hiện đầu tiên, hãy kiểm tra xem người dùng đã đăng nhập hay chưa và đẩy ngay màn hình tiếp theo? Tất cả đều có trong ViewDidLoad.


2
Điều này thực sự hoạt động, nhưng mục tiêu của tôi là hiển thị hình ảnh khởi chạy miễn là ứng dụng vẫn chờ phản hồi của máy chủ (cho dù đăng nhập thành công hay không). Cũng giống như ứng dụng Facebook ...
mmvie 12/12/11

2
Bạn luôn có thể có chế độ xem đầu tiên chỉ là một UIImage sử dụng cùng một hình ảnh với ảnh giật gân của bạn và trong phần kiểm tra nền để xem liệu đã đăng nhập và hiển thị chế độ xem tiếp theo hay chưa.
Darren

3

Nhanh chóng triển khai tương tự:

Nếu bạn sử dụng UINavigationControllerlàm điểm vào trong bảng phân cảnh

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

Đây là giải pháp hoạt động trên iOS7. Để tăng tốc độ tải ban đầu và không thực hiện bất kỳ quá trình tải không cần thiết nào, tôi có một UIViewcontroller hoàn toàn trống có tên "DUMMY" trong tệp Storyboard của tôi. Sau đó, tôi có thể sử dụng mã sau:

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

Tôi đề nghị tạo một MainViewController mới là Root View Controller của Navigation Controller. Để làm điều đó, chỉ cần giữ điều khiển, sau đó kéo kết nối giữa Bộ điều khiển Điều hướng và MainViewController, chọn 'Mối quan hệ - Bộ điều khiển Chế độ xem gốc' từ lời nhắc.

Trong MainViewController:

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

Hãy nhớ tạo các nối tiếp giữa MainViewController với bộ điều khiển chế độ xem Trang chủ và Đăng nhập. Hi vọng điêu nay co ich. :)


0

Sau khi thử nhiều phương pháp khác nhau, tôi đã có thể giải quyết vấn đề này bằng cách:

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

Nếu bạn không ở quá xa với Taylor, bạn có thể muốn cấu trúc lại một cái gì đó đơn giản hơn. Xem câu trả lời của tôi để biết chi tiết :)
followben
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.