1

Help!

I am new to XCode and now i am facing a problem.

When i use the following code in the app and create a new ViewController class LoginViewController.

In iPhone, the app work great. But when I test in iPad it crash and display the following content in the log:

2014-05-06 17:05:31.289 We Love HK[38711:60b] -[LoginViewController viewControllers]: unrecognized selector sent to instance 0x10942c3d0
2014-05-06 17:05:31.291 We Love HK[38711:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[LoginViewController viewControllers]: unrecognized selector sent to instance 0x10942c3d0'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001019fc495 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010175b99e objc_exception_throw + 43
    2   CoreFoundation                      0x0000000101a8d65d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x00000001019edd8d ___forwarding___ + 973
    4   CoreFoundation                      0x00000001019ed938 _CF_forwarding_prep_0 + 120
    5   We Love HK                          0x0000000100001086 -[AppDelegate application:didFinishLaunchingWithOptions:] + 246
    6   UIKit                               0x00000001003033d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 264
    7   UIKit                               0x0000000100303be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1605
    8   UIKit                               0x0000000100307a0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
    9   UIKit                               0x0000000100318d4c -[UIApplication handleEvent:withNewEvent:] + 3189
    10  UIKit                               0x0000000100319216 -[UIApplication sendEvent:] + 79
    11  UIKit                               0x0000000100309086 _UIApplicationHandleEvent + 578
    12  GraphicsServices                    0x0000000103b2b71a _PurpleEventCallback + 762
    13  GraphicsServices                    0x0000000103b2b1e1 PurpleEventCallback + 35
    14  CoreFoundation                      0x000000010197e679 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
    15  CoreFoundation                      0x000000010197e44e __CFRunLoopDoSource1 + 478
    16  CoreFoundation                      0x00000001019a7903 __CFRunLoopRun + 1939
    17  CoreFoundation                      0x00000001019a6d83 CFRunLoopRunSpecific + 467
    18  UIKit                               0x00000001003072e1 -[UIApplication _run] + 609
    19  UIKit                               0x0000000100308e33 UIApplicationMain + 1010
    20  We Love HK                          0x00000001000044b3 main + 115
    21  libdyld.dylib                       0x000000010207f5fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

And LoginViewController.h:

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import "KeychainItemWrapper.h"

@import Security;

@interface LoginViewController : UIViewController <UITextFieldDelegate>

@property (nonatomic, retain) IBOutlet UILabel *version_label;

@property (strong, nonatomic) IBOutlet UITextField *txtUsername;
@property (strong, nonatomic) IBOutlet UITextField *txtPassword;


- (IBAction) loginClicker:(id)sender;
- (IBAction) backgroundTap:(id)sender;
- (IBAction) keyboardDismiss: (id) sender;
- (IBAction) click_exit: (id)  sender;

@end

LoginViewController.m:

#import "LoginViewController.h"

@implementation LoginViewController;

@synthesize version_label;
@synthesize txtUsername;
@synthesize txtPassword;

-(void)viewDidLoad
{
    KeychainItemWrapper *keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"UserAuthToken" accessGroup:nil];
    NSString *version = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];  // Get App Version
    NSString *build = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"];  // Get App Build Number
    version_label.numberOfLines = 0;                               // Enable \n break line
    version_label.hidden = NO;                                     // Disable Hidden
    //[keychainWrapper resetKeychainItem];
    version_label.text = [NSString stringWithFormat:@"V %@ (Build %@)", version, build];    // Change Version Label's Content
     if ([keychainWrapper objectForKey:(__bridge id)(kSecAttrAccount)] && [keychainWrapper objectForKey:(__bridge id)(kSecValueData)]){
        txtUsername.text = [keychainWrapper objectForKey:(__bridge id)(kSecAttrAccount)];
        txtPassword.text = [keychainWrapper objectForKey:(__bridge id)(kSecValueData)];
    }
}

-(IBAction) keyboardDismiss: (id) sender{
    [txtUsername resignFirstResponder];
    [txtPassword resignFirstResponder];
}

- (IBAction)backgroundTap:(id)sender {
    [txtUsername resignFirstResponder];
    [txtPassword resignFirstResponder];
}

- (IBAction)click_exit:(id)sender {
    //[txtUsername resignFirstResponder];
    //[txtPassword resignFirstResponder];
}

- (IBAction)loginClicker:(id)sender {
    NSInteger success = 0;
    @try {

        if([[self.txtUsername text] isEqualToString:@""] || [[self.txtPassword text] isEqualToString:@""] ) {

            [self alertStatus:@"請輸入帳號及密碼!" :@"登入失敗!" :0];

        } else {
            KeychainItemWrapper *keychainWrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"UserAuthToken" accessGroup:nil];
            NSString *post =[[NSString alloc] initWithFormat:@"username=%@&password=%@",[self.txtUsername text],[self.txtPassword text]];
            NSLog(@"PostData: %@",post);

            NSURL *url=[NSURL URLWithString:@"http://ls.arefly.com/other/php/welovehk/login.php"];

            NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];

            NSString *postLength = [NSString stringWithFormat:@"%lu", (unsigned long)[postData length]];

            NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
            [request setURL:url];
            [request setHTTPMethod:@"POST"];
            [request setValue:postLength forHTTPHeaderField:@"Content-Length"];
            [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
            [request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
            [request setHTTPBody:postData];

            //[NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:[url host]];

            NSError *error = [[NSError alloc] init];
            NSHTTPURLResponse *response = nil;
            NSData *urlData=[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];

            NSLog(@"Response code: %ld", (long)[response statusCode]);

            if ([response statusCode] >= 200 && [response statusCode] < 300)
            {
                NSString *responseData = [[NSString alloc]initWithData:urlData encoding:NSUTF8StringEncoding];
                NSLog(@"Response ==> %@", responseData);

                NSError *error = nil;
                NSDictionary *jsonData = [NSJSONSerialization
                                          JSONObjectWithData:urlData
                                          options:NSJSONReadingMutableContainers
                                          error:&error];

                success = [jsonData[@"login_status"] integerValue];
                NSLog(@"Success: %ld", (long)success);

                if(success == 1)
                {
                    NSLog(@"Login SUCCESS");
                    [keychainWrapper setObject:[self.txtUsername text] forKey:(__bridge id)(kSecAttrAccount)];
                    [keychainWrapper setObject:[self.txtPassword text] forKey:(__bridge id)(kSecValueData)];
                    NSString *name_msg = (NSString *) jsonData[@"name_msg"];
                    [self alertStatus:name_msg :@"歡迎!" :0];
                } else {
                    NSString *error_msg = (NSString *) jsonData[@"error_message"];
                    [self alertStatus:error_msg :@"登入失敗!" :0];
                    txtPassword.text = @"";
                }

            } else {
                //if (error) NSLog(@"Error: %@", error);
                [self alertStatus:@"Connection Failed" :@"登入失敗!" :0];
                txtPassword.text = @"";
            }
        }
    }
    @catch (NSException * e) {
        NSLog(@"Exception: %@", e);
        [self alertStatus:@"登入失敗!" :@"錯誤:" :0];
        txtPassword.text = @"";
    }
    if (success) {
        [self performSegueWithIdentifier:@"login_success" sender:self];
    }

}

- (void) alertStatus:(NSString *)msg :(NSString *)title :(int) tag
{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
                                                        message:msg
                                                       delegate:self
                                              cancelButtonTitle:@"OK"
                                              otherButtonTitles:nil, nil];
    alertView.tag = tag;
    [alertView show];
}

@end

and here also didFinishLaunchingWithOptions in AppDelegate.m (but i do not think i change anything of it):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
        UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController;
        UINavigationController *navigationController = [splitViewController.viewControllers lastObject];
        splitViewController.delegate = (id)navigationController.topViewController;
    }
    return YES;
}

and here is my Main_iPad.storyboard:

http://uploadpie.com/rTIVc

and here is my Main_iPhone.storyboard:

http://uploadpie.com/gmpms

Can any one help me?

Thanks!

UPDATE

After i comment the whole if block in -(BOOL)application:didFinishLaunchingWithOptions:, its become ok and do not crash.

But there are other crash appear when i want to do [self performSegueWithIdentifier:@"login_success" sender:self];

2014-05-06 18:55:28.839 We Love HK[45660:60b] Success: 1
2014-05-06 18:55:28.839 We Love HK[45660:60b] Login SUCCESS
2014-05-06 18:55:28.887 We Love HK[45660:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present a Split View Controllers modally <LoginViewController: 0x109429ca0>.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001019fc495 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010175b99e objc_exception_throw + 43
    2   UIKit                               0x0000000100408c93 -[UIViewController presentViewController:withTransition:completion:] + 4027
    3   We Love HK                          0x0000000100005a35 -[LoginViewController loginClicker:] + 3813
    4   UIKit                               0x0000000100309f06 -[UIApplication sendAction:to:from:forEvent:] + 80
    5   UIKit                               0x0000000100309eb4 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 17
    6   UIKit                               0x00000001003e6880 -[UIControl _sendActionsForEvents:withEvent:] + 203
    7   UIKit                               0x00000001003e595d -[UIControl touchesBegan:withEvent:] + 219
    8   UIKit                               0x0000000100340b74 -[UIWindow _sendTouchesForEvent:] + 300
    9   UIKit                               0x00000001003416e4 -[UIWindow sendEvent:] + 925
    10  UIKit                               0x000000010031929a -[UIApplication sendEvent:] + 211
    11  UIKit                               0x0000000100306aed _UIApplicationHandleEventQueue + 9579
    12  CoreFoundation                      0x000000010198bd21 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
    13  CoreFoundation                      0x000000010198b5f2 __CFRunLoopDoSources0 + 242
    14  CoreFoundation                      0x00000001019a746f __CFRunLoopRun + 767
    15  CoreFoundation                      0x00000001019a6d83 CFRunLoopRunSpecific + 467
    16  GraphicsServices                    0x0000000103b29f04 GSEventRunModal + 161
    17  UIKit                               0x0000000100308e33 UIApplicationMain + 1010
    18  We Love HK                          0x00000001000045b3 main + 115
    19  libdyld.dylib                       0x000000010207f5fd start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

Also i want to know how can i set the splitViewController.delegate from a different place?

He Yifei 何一非
  • 2,592
  • 4
  • 38
  • 69
  • can you share viewdidload? – Macrosoft-Dev May 06 '14 at 09:14
  • @Arefly: show your code which create LoginViewController – nmh May 06 '14 at 09:15
  • Where do you call this -[LoginViewController viewControllers]:? Error is related to this. – Ricky May 06 '14 at 09:16
  • I've update the whole code of the file in the question. Thanks – He Yifei 何一非 May 06 '14 at 09:20
  • Your rootViewController is not a `UISPlitViewController` – Rukshan May 06 '14 at 09:42
  • @sleepwalkerfx how can i fix that? – He Yifei 何一非 May 06 '14 at 10:34
  • @Arefly what happens if you comment the whole `if` block in `-(BOOL)application:didFinishLaunchingWithOptions:`? And set the splitViewController.delegate from a different place? – Rukshan May 06 '14 at 10:57
  • after i comment the whole `if` block in `-(BOOL)application:didFinishLaunchingWithOptions:`, its become ok. And how can i set the splitViewController.delegate from a different place? PS: there are other crash appre after i click the button (i am not sure if it have anything with it) `2014-05-06 18:55:28.887 We Love HK[45660:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Application tried to present a Split View Controllers modally .'` – He Yifei 何一非 May 06 '14 at 11:06
  • @sleepwalkerfx sorry i am new to XCode and i am not quiet understand you. Can you explain how can i do? – He Yifei 何一非 May 06 '14 at 11:21
  • @Arefly uncomment the `if` block again and, set your splitViewcontroller as the initial ViewController. You can do this by selecting the splitViewcontroller from storyboard( zoom out first) and tick the option 'Is initial ViewController' , because Your splitViewController must be the initial ViewController always. You need a different mechanism to display login. – Rukshan May 06 '14 at 12:03
  • @sleepwalkerfx so you mean i need to set the Master Detail view to the default and use other ways to let Login Page display? But why the storyboard of iPhone is the same way and work? And can you teach me how can i use different mechanism to display login. Thanks! – He Yifei 何一非 May 06 '14 at 12:09
  • @Arefly your iPhone version has a UITabViewController, not a UISplitViewController. In iPad version SplitViewController (master detail) must be the initial ViewController. Once you do that, read this, http://stackoverflow.com/questions/3607787/how-to-add-a-login-view-before-a-uisplitviewcontroller-ipad – Rukshan May 06 '14 at 12:29

2 Answers2

6

You should propably share your application:didFinishLaunchingWithOptions: method.

I am pretty sure that somewhere there you are using LoginViewController is used as UINavigationController or UISplitViewController. That is why viewControllers method is called there.

According to your application:didFinishLaunchingWithOptions method, it crashes here

UINavigationController *navigationController = [splitViewController.viewControllers lastObject];

Probably you have wrong InitialViewController in your iPad storyboard

B.S.
  • 21,660
  • 14
  • 87
  • 109
  • Or a UISplitViewController. – gWiz May 06 '14 at 09:21
  • I've updated the whole LoginViewController.m in the question. Can help me solve? Thanks – He Yifei 何一非 May 06 '14 at 09:22
  • share you didFinishLaunchingWithOptions method, which is located in AppDelegate – B.S. May 06 '14 at 09:25
  • so how can i check if `InitialViewController` is wrong? i am new in XCode sorry... – He Yifei 何一非 May 06 '14 at 09:33
  • What do you want to be displayed in you iPad version? I am sure that Login Screen should do be displayed in UISplitViewController – B.S. May 06 '14 at 09:35
  • @George just display the content same as iPhone's Version. – He Yifei 何一非 May 06 '14 at 09:38
  • I do not imagine what content is displaying in your iPhone version, try to remove code from didFinishLaunchingWithOptions version, perhaps it will help if you have 1 storyboard for iPhone and iPad (just guessing, how it is implemented on your side) – B.S. May 06 '14 at 09:42
  • after i change the code to - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { return YES; } and it works in boths iPad and iPhone. Is it right? – He Yifei 何一非 May 06 '14 at 09:45
  • @George So what can i do to fix it? Thanks – He Yifei 何一非 May 06 '14 at 10:53
  • do you use the same storyboard? If yes, just remove the code if NO, look what is initial viewcontroller in you iPad storyboard - http://stackoverflow.com/questions/16329066/change-initial-view-controller-after-first-launch-of-app – B.S. May 06 '14 at 12:18
1

The exception clearly states that

[LoginViewController viewControllers]: unrecognized selector sent to instance

mean, the controller which is not present in the UIStoryBoard of iPad.

their will be 2 storyBoards in the project,

  • In iPhone, the app work great. So mean, you have created LoginViewController for only iPhone not for iPad's storyBoard.

    you need to create the LoginViewController in the iPad storyBoard as well.

Kumar KL
  • 15,315
  • 9
  • 38
  • 60