Как отобразить экран входа в систему до того, как контроллер корневого представления (PFQueryTableViewController) попытается выполнить запрос без пользователя и приведет к сбою программы

Я хочу, чтобы мой корневой контроллер представления программы, над которой я работаю, был PFQueryTableViewController, однако мне нужно приложение, чтобы убедиться, что пользователь вошел в систему до того, как PFQueryTableViewController попытается выполнить запрос.

Я попытался создать RootTabBarViewController, исходным видом которого является PFQueryTableViewController, и поместить следующее в файлы .h и .m RootTabBarViewController:

//
//  RootTabBarViewController.h
//

#import <UIKit/UIKit.h>
#import <Parse/Parse.h>

@interface RootTabBarViewController : UITabBarController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>

@end



//
//  RootTabBarViewController.m
//

#import "RootTabBarViewController.h"
#import "PlannrLogInViewController.h"

@interface RootTabBarViewController ()

@end

@implementation RootTabBarViewController

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

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

    if (![PFUser currentUser]) { // No user logged in
        // Create the log in view controller
        PFLogInViewController *logInViewController = [[PFLogInViewController alloc] init];
        [logInViewController setDelegate:self]; // Set ourselves as the delegate

        // Create the sign up view controller
        PFSignUpViewController *signUpViewController = [[PFSignUpViewController alloc] init];
        [signUpViewController setDelegate:self]; // Set ourselves as the delegate

        // Assign our sign up controller to be displayed from the login controller
        [logInViewController setSignUpController:signUpViewController];

        // Present the log in view controller
        [self presentViewController:logInViewController animated:YES completion:NULL];
    }
}
/*
#pragma mark - Navigation

// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/

#pragma mark - PFLoginViewController Delegate

// Sent to the delegate to determine whether the log in request should be submitted to the server.
- (BOOL)logInViewController:(PFLogInViewController *)logInController shouldBeginLogInWithUsername:(NSString *)username password:(NSString *)password {
    // Check if both fields are completed
    if (username && password && username.length != 0 && password.length != 0) {
        return YES; // Begin login process
    }

    [[[UIAlertView alloc] initWithTitle:@"Missing Information"
                                message:@"Make sure you fill out all of the information!"
                               delegate:nil
                      cancelButtonTitle:@"ok"
                      otherButtonTitles:nil] show];
    return NO; // Interrupt login process
}

// Sent to the delegate when a PFUser is logged in.
- (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user {
    [self dismissViewControllerAnimated:YES completion:NULL];
}

// Sent to the delegate when the log in attempt fails.
- (void)logInViewController:(PFLogInViewController *)logInController didFailToLogInWithError:(NSError *)error {
    NSLog(@"Failed to log in...");
}

// Sent to the delegate when the log in screen is dismissed.
- (void)logInViewControllerDidCancelLogIn:(PFLogInViewController *)logInController {
    [self.navigationController popViewControllerAnimated:YES];
}

#pragma mark - PFSignUpViewController Delegate

// Sent to the delegate to determine whether the sign up request should be submitted to the server.
- (BOOL)signUpViewController:(PFSignUpViewController *)signUpController shouldBeginSignUp:(NSDictionary *)info {
    BOOL informationComplete = YES;

    // loop through all of the submitted data
    for (id key in info) {
        NSString *field = [info objectForKey:key];
        if (!field || field.length == 0) { // check completion
            informationComplete = NO;
            break;
        }
    }

    // Display an alert if a field wasn't completed
    if (!informationComplete) {
        [[[UIAlertView alloc] initWithTitle:@"Missing Information"
                                    message:@"Make sure you fill out all of the information!"
                                   delegate:nil
                          cancelButtonTitle:@"ok"
                          otherButtonTitles:nil] show];
    }

    return informationComplete;
}

// Sent to the delegate when a PFUser is signed up.
- (void)signUpViewController:(PFSignUpViewController *)signUpController didSignUpUser:(PFUser *)user {
    [self dismissModalViewControllerAnimated:YES]; // Dismiss the PFSignUpViewController
}

// Sent to the delegate when the sign up attempt fails.
- (void)signUpViewController:(PFSignUpViewController *)signUpController didFailToSignUpWithError:(NSError *)error {
    NSLog(@"Failed to sign up...");
}

// Sent to the delegate when the sign up screen is dismissed.
- (void)signUpViewControllerDidCancelSignUp:(PFSignUpViewController *)signUpController {
    NSLog(@"User dismissed the signUpViewController");
}

@end

А вот мой файл .m для подкласса PFQueryTableViewController:

//
//  EventPFQueryTableViewController.m
//

#import "EventPFQueryTableViewController.h"
#import "Event.h"

@interface EventPFQueryTableViewController ()

@end

@implementation EventPFQueryTableViewController


- (id)initWithCoder:(NSCoder *)aDecoder{

    self = [super initWithCoder:aDecoder];
    if (self)
    {

        self.parseClassName = kEventListClassKey;
    }

    return self;
}

- (PFQuery *)queryForTable
{
    PFQuery *query = [Event query];
    [query whereKey:kEventListFieldKeyUser equalTo:[PFUser currentUser]];

    return query;
}
/*

@end

Однако код в функции viewDidLoad этого контроллера представления панели вкладок, похоже, не запускается до загрузки PFQueryTableViewController (первое представление контроллера представления корневой панели) и пытается выполнить запрос, потому что я все еще получаю исключение:

2014-07-10 20:46:04.226 Plannr[12810:60b] * Завершение работы приложения из-за необработанного исключения "NSInvalidArgumentException", причина: "Невозможно выполнить запрос сравнения для типа: (null)"

Как я могу убедиться, что журнал загружается задолго до EventPFQueryTableViewController? Заранее спасибо.


person pmmiv    schedule 11.07.2014    source источник


Ответы (1)


Во-первых, вы можете предотвратить сбой приложения, изменив метод - (PFQuery *)queryForTable вашего EventPFQueryTableViewController следующим образом:

if ([PFUser currentUser]) { //User logged in.

  PFQuery *query = [Event query];

  [query whereKey:kEventListFieldKeyUser equalTo:[PFUser currentUser]];

  return query;

}

else {

  [super objectsDidLoad:error]; //Return failed to turn off spinner.

  return nil;

}

Вы также хотите установить прослушиватель уведомлений для зарегистрированного события в вашем PFQueryTableViewController. Это будет вызвано, когда пользователь войдет в систему, чтобы обновить ваше табличное представление, назвав его чем-то вроде handleLogIn:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleLogIn:) name:kLoggedInEvent object:nil];

В вашем PFQueryTableViewController добавьте метод handleLogIn:

- (void)handleLogIn:(NSNotification*) notification {
  [self loadObjects]
}

Затем, когда регистрация/вход в систему завершатся успешно, вызовите созданное вами уведомление, чтобы обновить TableView:

[[NSNotificationCenter defaultCenter] postNotificationName:kLoggedInEvent object:nil userInfo:nil];

Надеюсь это поможет.

person penguinmaster    schedule 11.07.2014
comment
Спасибо! Это решение работает! Кажется, это обходной путь для моей первоначальной проблемы проверки текущего пользователя (и отображения входа/регистрации, если текущего пользователя нет) задолго до загрузки PFQueryTableView. Любые идеи о том, как решить эту проблему? - person pmmiv; 11.07.2014
comment
Я бы переместил то, что у вас есть в viewDidAppear, в viewDidLoad и загрузил PFLogInViewController. Это загрузит представление входа, если пользователь не вошел в систему. Но добавьте строку postNotificationName, о которой я упоминал выше, в - (void)logInViewController:(PFLogInViewController *)logInController didLogInUser:(PFUser *)user. Это вызовет метод уведомления handleLogIn, который обновит ваше табличное представление после входа пользователя. Убедитесь, что вы добавили Observer для уведомление в viewDidLoad вашего EventPFQueryTableViewController. - person penguinmaster; 11.07.2014
comment
Сработало ли мое решение? Если это так, пожалуйста, проверьте мой ответ. Если у вас есть более подробные вопросы, я буду рад помочь. - person penguinmaster; 11.07.2014