Challenge: Make a Data Source


#1

Hey This is my first time i’m writing here. I have received a LOT of great help from this site thank you. This is my solution:

#import <Cocoa/Cocoa.h>

@interface ChallengeAppDelegate : NSObject <NSApplicationDelegate,NSTableViewDataSource> {
NSMutableArray *itemList;
}

@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSTextField *_anewItemField;
@property (weak) IBOutlet NSTableView *_toDoTableView;

  • (IBAction)createNewItem:(id)sender;

  • (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView;

  •       (id)tableView:(NSTableView *)aTableView
    

objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row;

  • (id)init;
  • (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject;
    @end

#import “ChallengeAppDelegate.h”

@implementation ChallengeAppDelegate

@synthesize window;
@synthesize _anewItemField;
@synthesize _toDoTableView;

  • (void)applicationDidFinishLaunching:(NSNotification *)aNotification
    {
    // Insert code here to initialize your application
    }

  • (IBAction)createNewItem:(id)sender {
    NSString *newItem = [_anewItemField stringValue];
    NSLog(@"%@",newItem);

    [itemList addObject:newItem];
    [_toDoTableView reloadData];
    }

  • (id)init {
    self = [super init];
    if (self) {
    itemList = [[NSMutableArray alloc] init];
    NSLog(@“itemlist allocated…”);
    }
    return self;
    }

// Two methods I have to implement!

  • (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView {
    return [itemList count];
    }

  •       (id)tableView:(NSTableView *)aTableView
    

objectValueForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row {
NSString *i = [itemList objectAtIndex:row];
return i;
}

// And the one optional because we are aiming for the editable tableview!

  • (void)tableView:(NSTableView *)tableView
    setObjectValue:(id)object
    forTableColumn:(NSTableColumn *)tableColumn
    row:(NSInteger)row {
    // the datasource takes the input that the user put into row rowindex of aTableColumn.
    // this is necessary if you are going to have an editable tableview
    [itemList replaceObjectAtIndex:row
    withObject:object];
    [_toDoTableView reloadData];
    }

  • (void)replaceObjectAtIndex:(NSUInteger)index withObject:(id)anObject {
    [itemList replaceObjectAtIndex:index
    withObject];
    }

@end

Hope this helps somebody =)


#2

Great! This really helps me.


#3

Thanks that did it for me. I didn’t realize that - (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row and - (void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row are each others opposites. As in objectValue fills the tableViewCell and setObjectValue gets the value from the tableViewCell


#4

It didn’t help me at all. I don’t have any problem with the code an understanding it. My problem is that I cannot properly define the delegate for the TableView. I defined a new class and made it the delegate of the window in the NIB fuel. No result. I made NSMutableArray the delegate of the tableview, also no result.
Can somebody tell me what I’m doing wrong her?


#5

[quote]It didn’t help me at all. I don’t have any problem with the code an understanding it. My problem is that I cannot properly define the delegate for the TableView. I defined a new class and made it the delegate of the window in the NIB fuel. No result. I made NSMutableArray the delegate of the tableview, also no result.
Can somebody tell me what I’m doing wrong her?[/quote]
It looks like you are trying all possible permutations there :slight_smile:

What do you mean?

That doesn’t sound right. To start off, you need a class that implements the table-view delegate protocol. You make an instance of that class a delegate of the table view. That class will normally be one of your view controllers, but it does not have to be. (The same applies to table view data source.)

[Accelerate your learning and become a competent programmer: pretty-function.org]


#6

Hi ibex,

Thanks for the quick reply. Much appreciated. I defined a new class, called TDLController. In the MainMenu.xib file I added an NSObject in the document outline and in the identity inspector defined TDLContoller as the custom class. Then I control dragged from the connections inspector of the windows object from the delegate outlet to the TDLController object. This makes the newly defined class, TDLController, now the delegate of the window, right?

Then I defined the properties and actions in the TDLController.h file:

#import <Foundation/Foundation.h>

@interface TDLController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
@property (weak) IBOutlet NSTextField *anewItem;
@property (weak) IBOutlet NSButton *addItemButton;
@property (weak) IBOutlet NSTableView *listToDo;
@property NSMutableArray *theItems;

- (IBAction)addITem:(id)sender;

@end

then I implemented the methods in the TDLController.m file:

#import "TDLController.h"

@implementation TDLController

@synthesize anewItem;
@synthesize listToDo;
@synthesize theItems;

//Initialization method

-(id)init {
	self = [super init];
	
	if(self) {
		theItems = [[NSMutableArray alloc]init];
		[listToDo setDelegate];
	}
	return self;
}

//Methods providing the functionality to

- (IBAction)addITem:(id)sender {
	NSString *string = [anewItem stringValue];
	NSLog(@"The input string is: %@", string);
	
	[theItems addObject:string];
	[anewItem setStringValue:@""];
	[listToDo reloadData];
	
	for (NSString *i in theItems) {
		NSLog(@"%@", i);
	}
}

//Mandatory methods for NSTableViewDataSource

-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
	return [theItems count];
}

-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	NSString *string = [theItems objectAtIndex:row];
	return string;
}

-(void)tableView:(NSTableView *)tableView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
	[theItems replaceObjectAtIndex:row withObject:object];
}

@end

As you can see in the initialization method, I also declared the NSMutableArray to be the delegate of the tableView, but, sadly, without any succes.
I have no clue what I did wrong and now I’m reading throughout the TableView, Window and Concepts in Objective-C programming guides to find a clue of what to do better. :frowning: :confused:


#7

That’s good.

By windows object do you mean the TV (Table View)? If the answer is yes, then make sure that there are no errors in the names of TV’s delegate and data source protocol methods. Also in the awakeFromNib method of the controller, ask the TV to reload.

If the answer is no, then connect the TV’s data source and delegate outlets to the controller.

Also remember that a cell-based TV object operates slightly differently than a view-based TV object.


#8

Hi ibex,

Thanks for the help. I made the mistake by selecting the window object and connecting it to the Data Source, instead of the Table View. Still learning to work with the Interface Builder. I have a programming background that is over 20 years ago in C and industrial automation. We weren’t that much into GUIs and OO was not performing. Now Objective-C gives a lot of interesting options, but not everything makes immediate sense from my background. Or I’m just too slow. :confused:

Kind regards,
MacUserT