I know that this is a typical question, I found many threads talking about this, but I can't really understand where's the problem with my implementation. I set up everything and I'm able to see data loaded in a NSMutableArray inside my NSTableView. The problem is changing that data. What I do is:
-(void) setData:(NSMutableArray*)data{
for (int i=0; i<[data count]; i++){
[list addObject:[data objectAtIndex:i]];
}
[self reloadData];
}
I set up some debug logs to see if the method
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
was being called (as I was expecting) after [self reloadData], but it's not.
Just to be clear "setData" is placed inside the TableViewController that extends NSTableView and implements NSTableViewDataSource as well. So "self" should be right because refers to the actual NSTableView showed on the interface.
Edit
Here it is the code of the TableViewController.m:
#import "TableViewController.h"
#import "Transaction.h"
@implementation TableViewController
- (id) init
{
self = [super init];
if (self){
list = [self loadData];
//list = [[NSMutableArray alloc]init];
}
NSLog(@"init");
return self;
}
-(void) setData:(NSMutableArray*)data{
NSLog(@"setData");
[list removeAllObjects];
for (int i=0; i<[data count]; i++){
[list addObject:[data objectAtIndex:i]];
}
[self reloadData];
}
-(void)reloadData{
NSLog(@"reloadData. List: %ld",[list count]);
[super reloadData];
}
- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView{
return [list count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
NSLog(@"tableView");
Transaction *t = [list objectAtIndex:row];
if ([[tableColumn identifier] isEqualToString:@"date"]){
[[tableColumn headerCell] setTitle:@"Date"];
return [t date];
}
if ([[tableColumn identifier] isEqualToString:@"type"]){
[[tableColumn headerCell] setTitle:@"Type"];
return [t type];
}
if ([[tableColumn identifier] isEqualToString:@"category"]){
[[tableColumn headerCell] setTitle:@"Category"];
return [t category];
}
if ([[tableColumn identifier] isEqualToString:@"amount"]){
[[tableColumn headerCell] setTitle:@"Amount"];
return [NSString stringWithFormat:@"%f",[t amount]];
}
return @"//";
}
-(NSMutableArray *)loadData{
LoadSave* ls = [LoadSave alloc];
NSMutableArray* array = [[ls loadDataFromDisk] wallet];
for (Transaction* t in array){
//NSLog([t toString]);
}
// Load 1 row just to see if I can update the table later with more data
Transaction *t = [array objectAtIndex:1];
NSMutableArray * test = [NSMutableArray arrayWithObject:t];
return test;
}
@end
Header:
#import <Foundation/Foundation.h>
#import "Wallet.h"
#import "LoadSave.h"
@interface TableViewController : NSTableView <NSTableViewDataSource,NSTableViewDelegate> {
NSMutableArray *list;
}
-(void) setData:(NSMutableArray*)data;
-(IBAction)test:(id)sender;
- (id) initWithData:(NSMutableArray*)data;
@end
And this is for the moment my AppDelegate:
#import "AppDelegate.h"
#import "Transaction.h"
#import "TableViewController.h"
@implementation AppDelegate
@synthesize tableView;
@synthesize window;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
LoadSave* ls = [LoadSave alloc];
Wallet *wallet = [ls loadDataFromDisk];
tableView = [[TableViewController alloc]init];
[tableView setData: wallet.wallet ];
}
-(IBAction)test:(id)sender{
LoadSave* ls = [LoadSave alloc];
Wallet *wallet = [ls loadDataFromDisk];
[tableView setData: wallet.wallet ];
}
@end
As you can see I try to load new data both at the when the app finished launching and with a button on the interface. But nothing happen.
Edit 2:
This is the header of the AppDelegate, as you can see tableView is an instance of my controller class:
#import <Cocoa/Cocoa.h>
#import "TableViewController.h"
#import "LoadSave.h"
@interface AppDelegate : NSObject <NSApplicationDelegate>
@property (assign) IBOutlet NSWindow *window;
@property IBOutlet TableViewController *tableView;
-(IBAction)test:(id)sender;
@end
This is the SaveLoad.m It's just what I will use to save and load and import data from any file:
#import "LoadSave.h"
@implementation LoadSave
NSString *const PATH = @"file.csv";
- (NSString *) pathForDataFile
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *folder = @".";
folder = [folder stringByExpandingTildeInPath];
if ([fileManager fileExistsAtPath:folder] == NO)
{
[fileManager createDirectoryAtPath:folder withIntermediateDirectories:NO attributes:nil error:nil];
}
NSString *fileName = @"wallet.data";
return [folder stringByAppendingPathComponent: fileName];
}
- (void)saveDataToDisk:(id)wallet
{
NSString * path = [self pathForDataFile];
NSMutableDictionary *rootObject;
rootObject = [NSMutableDictionary dictionary];
[rootObject setValue:wallet forKey:@"wallet"];
[NSKeyedArchiver archiveRootObject:rootObject toFile: path];
}
-(Wallet*)loadDataFromDisk
{
NSDictionary* root = [NSKeyedUnarchiver unarchiveObjectWithFile:[self pathForDataFile]];
return [root valueForKey:@"wallet"];
}
-(NSMutableArray*) importDataFromCSV
{
NSString* contents = [NSString stringWithContentsOfFile:PATH
encoding:NSUTF8StringEncoding
error:nil];
NSArray* lines = [contents componentsSeparatedByString:@"\n"];
NSRange range;
range.location = 1;
range.length = [lines count]-1;
lines = [lines subarrayWithRange:range];
NSMutableArray *data = [[NSMutableArray alloc] init];
for (NSString* line in lines)
{
NSArray* fields = [line componentsSeparatedByString:@","];
Transaction *t = [[Transaction alloc] init:fields[0] transactionType:fields[1] transactionCategory:fields[3] transactionAmount:fields[6]];
[data addObject:t];
}
// wallet* wallet = [Wallet alloc];
// wallet.wallet = data;
// LoadSave *ls = [LoadSave alloc];
// [ls saveDataToDisk:wallet];
return data;
}
@end
I guess that the alloc without init is still working because I'm using the methods like they were static, but I didn't search how to make them static so far, so I left them like that for now.
Instead of describing the interface, I think that posting a picture of it would be easier..
At this point though.. I could have post the entire project here xD