0

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..

screen

At this point though.. I could have post the entire project here xD

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Eux
  • 482
  • 7
  • 16
  • You really, badly need a `[list removeAllObjects];` before the first line in `- setData:`... –  Nov 25 '12 at 21:02
  • Nothing changed (besides having a clean list every time) – Eux Nov 25 '12 at 21:04
  • I know, that's why it's a comment and not an answer. I just remarked that if it's a `setXXX:` method, it probably doesn't do, in its current form, what you expect it to do. –  Nov 25 '12 at 21:05
  • ah ok sorry, not really used to this website :P – Eux Nov 25 '12 at 21:26
  • 1
    Are you sure self is the table view and not the controller? Log self and see what you get. – rdelmar Nov 26 '12 at 01:15
  • BTW, you don't need to loop through the array to update list, just use [list addObjectsFromArray:data] – rdelmar Nov 26 '12 at 01:19
  • Have you set the delegate and datasource to the controller? – Anoop Vaidya Nov 26 '12 at 06:57
  • @rdelmar i know, but I need it for later. – Eux Nov 26 '12 at 08:03
  • @AnoopVaidya yes i did, i can visualize data. i didn't set the delegate only becouse i extend the NSTableView and i implemented the requested method in the extension. – Eux Nov 26 '12 at 08:07
  • so have you set delegate and datasource to that subclassed/extended class ? – Anoop Vaidya Nov 26 '12 at 08:31
  • Have you put a log in setData: to make sure it's being called? You really need to post more code -- you haven't shown enough for us to see what's going on. – rdelmar Nov 26 '12 at 15:29
  • @rdelmar here it is, i edited the first post with the important stuffs.. And yes, i logged setData and it's being called. PS: Thanks all for the help :) – Eux Nov 26 '12 at 19:30
  • Also, the interface should be set well because I can see the first data I load into the table. My problem is just updating it – Eux Nov 26 '12 at 19:32
  • A couple more questions. What is tableView in your app delegate? Is it an IBOutlet to a table view in IB? Also, what you've done with LoadSave is strange -- you have an alloc with no init. I'm surprised that works at all. What does the method loadDataFromDisk look like? – rdelmar Nov 26 '12 at 21:20
  • In addition to my questions above, you should describe whatever you've done in IB. Did you add any blue object cubes? Did you set the class of the table view to TableViewController? What is the file's owner set to? Did you set the data source in IB (I don't see that you did it in code)? – rdelmar Nov 26 '12 at 23:43
  • There, new edit. I hope this makes things more clear :D – Eux Nov 27 '12 at 09:37
  • As usual the method "Delete and redo" worked. Sadly I didn't find out where was the error but I'm quite sure it was something quite stupid as always. I just made again interface and controller and everything's working ^^ Thanks anyway for your help :) – Eux Nov 27 '12 at 19:48

0 Answers0