Build Failed


#1

Hi,

When building the app, I get a Build failed notification. Xcode says “Use of undeclared identifier addTask”. Here’s my code:
iTahDoodle.m

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

@implementation SKAppDelegate

#pragma mark - Application delegate callbacks

  • (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
    {
    return [tasks count];
    }

  • (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
    {
    UITableViewCell *c = [taskTable dequeueReusableCellWithIdentifier:@“Cell”];

    if (!c) {
    c = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@“Cell”];
    }

    NSString *item = [tasks objectAtIndex:[indexPath row]];
    [[c textLabel]setText:item];

    return c;
    }

  • (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
NSArray *plist = [NSArray arrayWithContentsOfFile:docPath()];
if (plist)
{
tasks = [plist mutableCopy]; //If there is a dataset available, copy it into our instance variable

}else{
    tasks = [[NSMutableArray alloc]init]; //Otherwise, create an empty one
}

if ([tasks count] == 0)
{
    [tasks addObject:@"Walk the dogs"];
    [tasks addObject:@"Finish this book"];
    [tasks addObject:@"Chop the logs for christmas"];
}

CGRect windowFrame = [[UIScreen mainScreen]bounds];
UIWindow *theWindow = [[UIWindow alloc]initWithFrame:windowFrame];
[self setWindow:theWindow];

CGRect tableFrame = CGRectMake(0, 80, 320, 380);
CGRect fieldFrame = CGRectMake(20, 40, 200, 31);
CGRect buttonFrame = CGRectMake(228, 40, 72, 31);

taskTable = [[UITableView alloc]initWithFrame:tableFrame
                                        style:UITableViewStylePlain];
[taskTable setSeparatorStyle:UITableViewCellSeparatorStyleNone];
[taskTable setDataSource:self];

taskField = [[UITextField alloc]initWithFrame:fieldFrame];
[taskField setBorderStyle:UITextBorderStyleRoundedRect];
[taskField setPlaceholder:@"Type a task, tap Insert"];

insertButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[insertButton setFrame:buttonFrame];
[insertButton addTarget:self
                 action:@selector(addTask:)
       forControlEvents:UIControlEventTouchUpInside];
[insertButton setTitle:@"Insert" forState:UIControlStateNormal];

[[self window]addSubview:taskTable];
[[self window]addSubview:taskField];
[[self window]addSubview:insertButton];

[[self window]setBackgroundColor: [UIColor whiteColor]];
[[self window]makeKeyAndVisible];
 
return YES;

- (void)addTask:(id)sender
{
    NSString *t = [taskField text];
    if ([t isEqualToString:@""])
    {
        return;
    }
}
[tasks addObject:t];
[taskTable reloadData];
[taskField setText:@""];
[taskField resignFirstResponder];

}[/code]

iTahDoodle.h

[code]NSString *docPath(void);

@interface SKAppDelegate : UIResponder <UIApplicationDelegate, UITableViewDataSource>

{
UITableView * taskTable;
UITextField * taskField;
UIButton * insertButton;

NSMutableArray *tasks;

}

  • (void)addTask:(id)sender;

@property (strong, nonatomic) UIWindow *window;

@end[/code]
I have checked everything multiple times but cannot find the error… Thanks for any help!


#2

You have defined the method - (void)addTask:(id)sender inside another method. In the C Programming language, you can’t do that.


#3

So what do you do to change it?


#4

In Objective-C, nested method definitions are not allowed:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
     ...
     return YES;
    ...
    - (void)addTask:(id)sender
    {
        NSString *t = [taskField text];
        if ([t isEqualToString:@""])
        {
            return;
        }
    }
    ...
}

You must define it outside of the method application:didFinishLaunchingWithOptions: :

- (void)addTask:(id)sender
{
        NSString *t = [taskField text];
        if ([t isEqualToString:@""])
        {
            return;
        }
}

#5

I am getting the same error for addTask. Code is directly from the book. Is the book code inaccurate?

.h

[code]
#import <UIKit/UIKit.h>

/* we add a C helper function that returns the file path of the property list (an XML file) that will store the user’s tasks. To add the helper function, you first have to declare it in BNRAppDelegate.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);

/* docPath() is declared above the class declaration because even though it is declared in the file BNRAppDelegate.h, it is not part of the BNRAppDelegate class */

/* In order for the table view’s data source to do its job, it must implement methods in the UITableViewDataSource protocol. First, we update BNRAppDelegate.h to declare that BNRAppDelegate conforms to this protocol */
@interface BNRAppDelegate : UIResponder <UIApplicationDelegate, UITableViewDataSource>

{
/* We are adding four instance variables - the first three are pointers that the user can see and interact with: */

// 1) a table view that will display all the tasks to be done
UITableView *taskTable;

// 2) a text field where you can enter a new task
UITextField *taskField;

// 3) a button that will add the new task to the table
UIButton *insertButton;

// the fourth is a mutable array where you will store the tasks as strings
NSMutableArray *tasks;

}

  • (void)addTask:(id)sender;

@property (strong, nonatomic) UIWindow *window;

@end[/code]

and .m

#import "BNRAppDelegate.h"

/* Reminder - because docPath() is not part of the class, implement it AFTER IMPORT and BEFORE @IMPLEMENTATION, which is where the implementation of the class begins */

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

@implementation BNRAppDelegate

{

#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 the instance variable.
        tasks = [plist mutableCopy];
        
    } else {
        // Otherwise, just 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"];
    }
    
    
    // Creat and configure the UIWindow instance
    // A CGRect is a struct with a n 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];
    
    // Make this object the table view's dataSource
    
    [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 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 he window and put it on the screen
    
    [[self window] setBackgroundColor:[UIColor whiteColor]];
    [[self window] makeKeyAndVisible];
    
    return YES;
    
    
       
       
}

/* START WITH THE CODE FOR THE TABLE VIEW MANAGEMENT */

#pragma mark - Table View management

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section

{
    /* Because this table view 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 the cells in memory that have scrolled off the screen and hand them back with new contents instead of always creating new cells. */
    
    // First, we check to see if there is 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]];
    
    // and hand back to the table view the properly configured cell
    
    return c;
    
    
}
// END TABLE VIEW CODE


- (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
{
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (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
{
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

@end

I am getting a successful build, but am only getting the text input box and the button. The list is not appearing.