Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

I'm a Mac

macrumors 6502
Original poster
Nov 5, 2007
436
0
I'm a little stuck on one of Hillegasses' challenges. The challenge is to make a ToDo app with NSTableView where you add an event from a textfield and extra points if it's editable. However, I can't get the events to add

Here's my appcontroller.m
Code:
#import "AppController.h"


@implementation AppController
-(id) init
{
	[super init];
	toDoList = [[NSMutableArray alloc] init];
}

-(int)numberOfRowsInTableView:(NSTableView *)tv
{
	return [toDoList count];
}

-(id)tableView:(NSTableView *)tv
	objectValueForTableColumn:(NSTableColumn *)tableColumn
		   row:(int)row {
	
NSString *toDo =  [toDoList objectAtIndex:row];
	return toDo;
	
}

-(void)tableViewSelectionDidChange:(NSNotification *)notification
{
	int row = [toDoTableView selectedRow];
	if (row == -1) {
		return;
	}
	NSString *selectedItem = [toDoList objectAtIndex:row];
	NSLog (@"new thing to do = %@", selectedItem);

}

-(IBAction)createNewItem:(id) sender
{
	NSString *item = [newItemField stringValue];
	if ([item length] == 0) {
		return;
	}
		NSInteger row = [toDoTableView selectedRow];
	if (row == -1){
		return;
	}
	{[toDoList insertObject:item atIndex:row];
		
	}
	{NSLog(@" have added %@ to list", item);
		
	}
		
	}

At one point it would log that I added the events but still it wouldn't show, now, for some reason it doesn't do that anymore. I really appreciate you help.
Also, I've tried the addOject method but that doesn't work either.
 
You must tell the NSTableView to reload it's data. This syncs the dataSource with the NSTableView for newly added or removed data.

Code:
[toDoTableView reloadData];

Put that in after the NSLog() function when you added your new todo item.

Hope it works, took me a while getting my head around TableViews.
 
EDIT: thanks, I got it to work. I changed it back to addObject and deleted some unecessary { characters.

EDIT #2: Okay, so I tried to make this editable, with some success. So when the user selects an item, it replaces that one (like it should but makes a duplicate, so now there are two of the newly added(changed) items

Code:
-(IBAction)createNewItem:(id) sender
{
	NSString *item = [newItemField stringValue];
	if ([item length] == 0) {
		return;
	}
	[toDoList addObject:item];
		NSLog(@" have added %@ to list", item);
		[toDoTableView reloadData];
	NSInteger row = [toDoTableView selectedRow];
	if (row == -1) {
		return;
	}
	[toDoList replaceObjectAtIndex:row withObject:item];
	NSLog(@"have changed event to %@", item);
	[toDoTableView reloadData];
	}

Also, I get a warning in my init method that the "control reaches end of non-void function. I have no idea as to what that means, but I do know that it is good practice not to ignore warnings- any ideas as to what I should do?

here's my init method
Code:
{
	[super init];
	toDoList = [[NSMutableArray alloc] init];
}
 
You and I are about in the same place in that Hillegass book. I was able to get this to work OK. Would you like to see the code I wrote or would you prefer for me give you hints on how I was able to get it to work?
 
Also, I get a warning in my init method that the "control reaches end of non-void function. I have no idea as to what that means, but I do know that it is good practice not to ignore warnings- any ideas as to what I should do?

here's my init method
Code:
{
	[super init];
	toDoList = [[NSMutableArray alloc] init];
}

The line above reads like:

-(id) init

so you are returning an object of type id, but this isn't really specified in the init method above. I would try adding this:

return self;

This way the method returns an object of type AppController, which is also an object of type id.

I would also suggest not using id unless you really needed to. Try specifying the object to be returned with

-(AppController *) init
 
thanks for your help everyone- and yes- return self worked. I'm impressed (although this was very simple for you experienced programmers) with myself for being able to do this mostly on my own- but I appreciate your help a lot, and I can't believe it wouldn't work just because of something that simple- but I guess that's programming.
 
I can't believe it wouldn't work just because of something that simple- but I guess that's programming.

Heh, that's programming in a nutshell. One missing bracket, or one in the wrong spot can mean the world of difference, as the computer will do EXACTLY what you tell it to do, which is not necessarily what you mean to do.

Case in point: the whole Zune shutdown of the last few days was caused by a similarly simple bug:
Code:
while (days > 365)
    {
        if (IsLeapYear(year))
        {
            if (days > 366)
            {
                days -= 366;
                year += 1;
            }
        }
        else
        {
            days -= 365;
            year += 1;
        }
    }

So in this case, if it a leap year, and days=366 as it was on Dec 31, you are stuck forever in that loop (at least until the next day)- so no more music for you!

So the moral is, even small things in code can have big ramifications. As you've noted, heeding warnings early on can spare you a lot of pain later.
 
Hi,

I'm running through this challenge now...

I registered just now to take note on a few things. I don't know if its better or worst, but what I've done seems to be working for me pretty well.

Code:
@interface AppController : NSObject {
	
	IBOutlet NSTableView *tableView;
	IBOutlet NSTextField *textField;
	IBOutlet NSButton *addButton;
	
	NSMutableArray *todoList;	
}

- (IBAction)createNewItem:(id)sender;

1. In the init I use the following:
Code:
todoList = [[NSMutableArray array] retain];

2. My action method createNewItem is as simple as this:
Code:
- (IBAction)createNewItem:(id)sender {
	NSString *item = [textField stringValue];
	
	if ([item length] == 0) {
		return;
	}

	[todoList addObject:item];
	NSLog(@"Adding TODO item to list: %@", item);
	[tableView reloadData];[textField setStringValue:@""];
	
	return;
}

3. For the last piece of the challenge is to make the table view editable. In the reading use the table view setter delegate:
Code:
- (void)tableView:(NSTableView *)tableview
   setObjectValue:(id)object
   forTableColumn:(NSTableColumn *)tableColumn
	            row:(int)row {
	
	if (row == -1) {
		return;
	}
	
	[todoList replaceObjectAtIndex:row withObject:(NSString *)object];
	NSLog(@"Changed TODO item in list: %@", [todoList objectAtIndex:row]);
	[tableView reloadData];
	
	return;
}

One last note, if you are over-thinking something, then you are most likely not tackling the challenge correctly.
Go back and re-read a little bit of the chapter.

Hope this helps someone.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.