Register FAQ / Rules Forum Spy Search Today's Posts Mark Forums Read
Go Back   MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Reply
 
Thread Tools Search this Thread Display Modes
Old Jan 26, 2012, 01:49 PM   #1
chrono1081
macrumors 603
 
chrono1081's Avatar
 
Join Date: Jan 2008
Location: Isla Nublar
Applications are expected to have a root view controller...?

Hi guys,

Sorry for the strange title its too long to fit in there.

I was following along in the Big Nerd Ranch Objective-C book and I ran into an issue and I haven't found the solution on the books forums or on Stack Overflow, and I think its in part because I don't understand the error. (I haven't touched Cocoa in a long time so its almost like its new to me again).

Here is the issue:

I run a program, it works fine even if I open and close it, however, if I kill it from the task manager and I reopen it I get this error:

"Applications are expected to have a root view controller at the end of application launch"

From researching, it looks like this error can stem from two places, the main.m file and the appdelegate.m file in the method:

Code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
The code is typed correctly from the book but I don't know enough about Cocoa to know how to fix it. Can anyone help me understand what this error stems from and how to fix it?

Here is my main.m file:

Code:
int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([BNRAppDelegate class]));
    }
}
Here is my AppDelegate file:

Code:
#import "BNRAppDelegate.h"

//Helper function to fetch the path to our to-do data stored on disk
NSString *docPath(void)
{
    NSArray *pathList = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
                                                            NSUserDomainMask,
                                                            YES);
    
    return [[pathList objectAtIndex:0] stringByAppendingPathComponent:@"data.td"];
}

@implementation BNRAppDelegate

@synthesize window = _window;

-(void) addTask:(id)sender
{
    //Get the to-do item
    NSString *t = [taskField text];
    
    //Quit here if the taskField is empty
    if([t isEqualToString:@""])
    {
        return;
    }
    
    //Add it to our working array
    [tasks addObject:t];
    
    //Refresh thetable so that the new item shows up
    [taskTable reloadData];
    
    //And clear our the text field
    [taskField setText:@""];
    
    //Dismiss the keyboard
    [taskField resignFirstResponder];
}

#pragma mark - Application delegate callbacks

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //Attempt to load an existing to-do dataset from an array stored to disk
    NSArray *plist = [NSArray arrayWithContentsOfFile:docPath()];
    
    if(plist)
    {
        //If there was a dataset available, copy it to our instance variable
        tasks = [plist mutableCopy];
    }
    
    else
    {
        //Otherwise, jsut create an empty one to get us started
        tasks = [[NSMutableArray alloc] init];
    }
    
    //Is tasks empty?
    if([tasks count] == 0)
    {
        //Put some strings in it
        [tasks addObject:@"Walk the dogs"];
        [tasks addObject:@"Feed the hogs"];
        [tasks addObject:@"Chop the logs"];
    }
    
    //Create and configure the UIWindow instance
    //A CGRect is a struct with an origin (x,y) and size (width,height)
    CGRect windowFrame = [[UIScreen mainScreen] bounds];
    UIWindow *theWindow = [[UIWindow alloc] initWithFrame: windowFrame];
    [self setWindow:theWindow];
    
    //Define the frame rectangles of the three UI elements
    //CGRectMake() creates a CHRect from (x, y, width, height)
    CGRect tableFrame  = CGRectMake(0, 80, 320, 380);
    CGRect fieldFrame  = CGRectMake(20, 40, 200, 31);
    CGRect buttonFrame = CGRectMake(228, 40, 72, 31);
    
    //Create and configure the table view
    taskTable = [[UITableView alloc] initWithFrame: tableFrame
                 style:UITableViewStylePlain];
    [taskTable setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    
    //Make this object the table view's dataSource
    [taskTable setDataSource:self];
    
    //Create and configure the text field where new tasks will be types
    taskField = [[UITextField alloc] initWithFrame: fieldFrame];
    [taskField setBorderStyle:UITextBorderStyleRoundedRect];
    [taskField setPlaceholder:@"Type a task, tap Insert"];
    
    //Create and configure a rounded rect Insert button
    insertButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [insertButton setFrame:buttonFrame];
    
    //Buttons behave using a target/action callback
    //Configure the Insert button's action to call this object's -addTask: method
    [insertButton addTarget:self 
                     action:@selector(addTask:) 
           forControlEvents:UIControlEventTouchUpInside];
    
    //Give the button a title
    [insertButton setTitle:@"Insert"
                  forState:UIControlStateNormal];
    
    //Add our three UI elements to the window
    [[self window] addSubview:taskTable];
    [[self window] addSubview:taskField];
    [[self window] addSubview:insertButton];
    
    //Finalize the window and put it on the screen
    [[self window] setBackgroundColor: [UIColor whiteColor]];
    [[self window] makeKeyAndVisible];
    
    return YES;
    
}

#pragma mark - Table View Management
-(NSInteger)tableView:(UITableView *)tableView 
numberOfRowsInSection:(NSInteger)section
{
    //Because this tableview only has one section, the number of rows
    //in it is equal to the number of items in our tasks array
    return [tasks count];
}

-(UITableViewCell *)tableView:(UITableView *)tableView 
        cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //To improve performance, we reconfigure cells in memory
    //that have scrolled off screen and hand them back
    //with the new contents instead of always creating new cells.
    
    //First we check to see if there's a cell available for reuse.
    UITableViewCell *c = [taskTable dequeueReusableCellWithIdentifier:@"Cell"];
    
    if(!c)
    {
        //...and only allocate a new cell if none are available
        c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
    }
    
    //Then we (re)configure the cell based on the model object, 
    //in this case our todoItems array
    NSString *item = [tasks objectAtIndex:[indexPath row]];
    [[c textLabel] setText:item];
    
    //and hand back to the table view the properly configured cell
    return c;
}

- (void)applicationWillResignActive:(UIApplication *)application
{
    /*
     Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
     Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
     */
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    //Save array to disk (iOS4+ only)
    [tasks writeToFile:docPath() atomically:YES];
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    /*
     Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
     */
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    /*
     Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
     */
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    //iOS 3 or below
    //Save our array to disk
    [tasks writeToFile:docPath() atomically:YES];
}

@end

Now, when I kill the program from the task manager and reopen I get this:

"Thread 1: Program received signal: "SIGKILL". and the line:

Code:
return UIApplicationMain(argc, argv, nil, NSStringFromClass([BNRAppDelegate class]));
in main.m is highlighted.

Sorry for the long post but I didn't want to not include anything. Can someone please explain why my program crashes like this? The last question about this on the books forum went unanswered : /
__________________
Macbook Air 13inch Ultimate
Hexcore MacPro 3.33ghz - 24 gigs ram - ATI 5870 - Dual 27inch ACD's
chrono1081 is offline   0 Reply With Quote
Old Jan 27, 2012, 02:30 AM   #2
jnoxx
macrumors 65816
 
jnoxx's Avatar
 
Join Date: Dec 2010
Location: Aartselaar // Antwerp // Belgium
First of all, debugger can't handle it if you close the app while connected via xcode, and reboot it again, it will send u a sigkill, it's not your code, it's the debugger so you will have to just deal with that sadly enough.
About the applications expected to have a rootController.
You are just adding subviews to your mainwindow instead of setting the rootViewController (of where the app should start), to the mainwindow. That's why it's guesing there is no rootController.
Simple as that actually
I think you can do.
[self.window setRoot(lala)];
__________________
CSS (Counter Strike Source) Tribute - iPad application
iPad Mini, iPad 4, iPad 2, iPhone 3G,4,5, iMac 24", Mac Mini Last gen, Macbook Pro with Dell U2711
jnoxx is offline   0 Reply With Quote
Old Jan 27, 2012, 11:20 AM   #3
chrono1081
Thread Starter
macrumors 603
 
chrono1081's Avatar
 
Join Date: Jan 2008
Location: Isla Nublar
Quote:
Originally Posted by jnoxx View Post
First of all, debugger can't handle it if you close the app while connected via xcode, and reboot it again, it will send u a sigkill, it's not your code, it's the debugger so you will have to just deal with that sadly enough.
About the applications expected to have a rootController.
You are just adding subviews to your mainwindow instead of setting the rootViewController (of where the app should start), to the mainwindow. That's why it's guesing there is no rootController.
Simple as that actually
I think you can do.
[self.window setRoot(lala)];
Thanks so much! Its been driving me nuts trying to figure that out

Its been two years roughly since I touched Cocoa Touch so I'm relearning it all over again :/
__________________
Macbook Air 13inch Ultimate
Hexcore MacPro 3.33ghz - 24 gigs ram - ATI 5870 - Dual 27inch ACD's
chrono1081 is offline   0 Reply With Quote

Reply
MacRumors Forums > Apple Systems and Services > Programming > iPhone/iPad Programming

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

Similar Threads
thread Thread Starter Forum Replies Last Post
Resolved: Loading a Progmatically created view Controller LastLine iPhone/iPad Programming 3 Apr 27, 2011 09:25 PM
How would I access a label on another view controller? KiranPanesar iPhone/iPad Programming 11 Apr 19, 2011 10:15 AM
How to create a template view controller? mikezang iPhone/iPad Programming 0 Sep 6, 2010 12:26 AM
Modal View Controller from Root View Controller in UISplitViewController seepel iPhone/iPad Programming 3 Aug 11, 2010 02:58 PM
Confused: What new portables are expected to be announced? Winstonp Mac Pro 10 Jan 3, 2006 11:40 AM


All times are GMT -5. The time now is 12:08 AM.

Mac Rumors | Mac | iPhone | iPhone Game Reviews | iPhone Apps

Mobile Version | Fixed | Fluid | Fluid HD
Powered by vBulletin® Version 3.8.6
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.

Privacy / DMCA contact / Affiliate and FTC Disclosure
Copyright 2002-2013, MacRumors.com, LLC