iTahDoodle closes immediately in simulator - no error


#1

I got to page 185 where you are meant to be able to see everything that you have created so far on the iPhone simulator. Instead, it opens and closes straight away without me seeing any screen.
My code is:

//  BNRAppDelegate.h
//  iTahDoodle

#import <UIKit/UIKit.h>

//Declare a helper function that we will use to get a path
//to a location on disk where we can save the to-do list
NSString *docPath(void);

@interface BNRAppDelegate : UIResponder <UIApplicationDelegate, UITableViewDataSource>
{
    UITableView *taskTable;
    UITextField *taskField;
    UIButton *insertButton;
    
    NSMutableArray *tasks;
}

-(void)addTask:(id)sender;

@property (strong, nonatomic) UIWindow *window;

@end
//  BNRAppDelegate.m
//  iTahDoodle

#import "BNRAppDelegate.h"

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

@implementation BNRAppDelegate

@synthesize window = _window;

#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 into our instance variable
        tasks = [plist mutableCopy];
    } else {
        //otherwise create an empty one just to get us started
        tasks = [[NSMutableArray alloc] init];
    }
    
    //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 CGRect 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];
    
    [taskTable setDataSource:self];
    
    //Create and configure the text field where new tasks will be typed
    taskField = [[UITextField alloc] initWithFrame:fieldFrame];
    [taskField setBorderStyle:UITextBorderStyleRoundedRect];
    [taskField setPlaceholder:@"Type a task, tap Insert"];
    
    //Create and configure rounded rectangle insert button
    insertButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [insertButton setFrame:buttonFrame];
    
    //Buttons behave using a target/acion callback
    //configure the insert buttons action to call this objects -addTask: method
    [insertButton addTarget:self action:@selector(addTask:) forControlEvents:UIControlEventTouchUpInside];
    
    //Give button a title
    [insertButton setTitle:@"Insert" forState:UIControlStateNormal];
    
    //Add out three UI elements to the dinwo
    [[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;
    
}

- (void)applicationWillResignActive:(UIApplication *)application
{
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
}

- (void)applicationWillEnterForeground:(UIApplication *)application
{
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
}

- (void)applicationWillTerminate:(UIApplication *)application
{
}

@end

#2

As to your code, the only thing that jumps out at me is that you’ve set self as the dataSource of the taskTable, but we’re not there yet as of p.185; the table view’s dataSource is required to implement a handful of callbacks in order to give the table view the information it needs to display.

Try commenting out the line [taskTable setDataSource:self]; for now (at least until you’re ready to implement the dataSource callbacks) and see what happens.

Regarding the lack of useful information from Xcode about what’s wrong, the application is probably throwing an exception that’s disappearing before we get to see it. Also, the current build of Xcode has a problem preventing the proper display of thrown exceptions.

Let’s address both to see if we can get some useful information about the problem.

  1. If you open up the Xcode preferences, under the Behaviors tab, you can instruct Xcode to leave the debug console open after a test completes.

  2. Set an Exception Breakpoint to make sure that Xcode properly notices when something goes wrong in your application. (You shouldn’t have to do this - Xcode has historically shown exceptions automatically). Click the [+] button at the bottom of the Breakpoint Navigator and select Exception Breakpoint. The default configuration for the breakpoint will do.

Build and run the application again, and see if the debug console (bottom pane) displays any useful information or error messages.
Best,
~Mikey


#3

That’s great! It is now working and I can see information in the debug area. Thanks!