How to get a dynamically changing NSTableView in OSX - objective-c

I am new to coding for Mac. I am familiar with UITableView's from iOS coding, but can't seem to get NSTableView to work properly on my app. Yes I have looked through documentation and tutorials, but I am having trouble getting the result I need. My desired outcome should be pretty basic and simple, but I am stumped on the TableViews. I would really like it to function more like how it does with a UITableView rather than how it seems to want to function with NSTableView. I don't want to add or remove rows. I only need 1 column and I would really like for it to work like a list of buttons that can be pressed and trigger the content associated with that option on the same screen on the next NSView over.
(I have 3 views on one screen. The first is the main menu to the left and when pressed triggers the tableView to display the submenu. When that option is selected it opens the content on the far right of the screen. My desired result anyways.)
Currently nothing is populating the tableview. This is what it currently looks like.
.h
#interface RootViewController : NSViewController <NSTableViewDataSource>{
IBOutlet NSView *mainMenuView;
IBOutlet NSTableView *tableView;
NSMutableArray *options;
}
-(IBAction)mainMenuBtn:(id)sender;
#end
.m
#interface RootViewController ()
#end
#implementation RootViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
options = [[NSMutableArray alloc] init];
}
return self;
}
-(void)viewDidLoad{
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return [options count];
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
return [[options objectAtIndex:row] valueForKey:[tableColumn identifier]];
}
-(IBAction)mainMenuBtn:(id)sender{
NSLog(#"1");
[options addObject:#"Strain 1"];
NSString *test = [options objectAtIndex:0];
NSLog(test);
[tableView reloadData];
}
Currently I have tableView connected in the NIB to the TableView. I attempted to connect dataSource to File's Owner, but that didn't work. Can't seem to find any place else to hook it up too. Any suggestions would be greatly appreciated. Thanks

First the dataSource of the NSTableView must be connected to your RootViewController instance in Interface Builder, or through code.
Something that seems a little suspicious to me is the line:
return [[options objectAtIndex:row] valueForKey:[tableColumn identifier]];
I don't know what is the value for the [tableColumn identifier] but it must match the property of the objects you're adding to your array. I can see that the objects you're adding are strings, so [tableColumn identifier] must be a property of class NSString. If you're using a string as the array's object, try using this:
return [options objectAtIndex:row];

Related

How to use NSCollectionViewItem without subclassing it?

I am writing a very simple macOS application that I'd like to show a few images in a collection view. I don't need any special behavior for how they are displayed. The docs for NSCollectionViewItem say:
The default implementation of this class supports the creation of a simple item that displays a single image or string.
That is what I want. However, I can't find any information on how to create a default NSCollectionViewItem.
The documentation for NSCollectionView states:
Every data source object is required to implement the following methods:
collectionView:numberOfItemsInSection:
collectionView:itemForRepresentedObjectAtIndexPath:
The second method above returns an NSCollectionViewItem. From reading examples I gather that the traditional way of creating an NSCollectionViewItem in this case is to call:
NSCollectionViewItem* newCollectionViewItem = [imageCollectionView makeItemWithIdentifier:<some identifier>
forIndexPath:indexPath];
The problem is that I don't understand what <some identifier> should be. I don't have a nib that contains an NSCollectionViewItem because I'm not subclassing it or customizing it in any way. I've tried adding the following to my data source:
- (void)awakeFromNib
{
[imageCollectionView registerClass:[NSCollectionViewItem class]
forItemWithIdentifier:#"Image"];
}
where imageCollectionView is the NSCollectionView in question. And then in my - (NSCollectionViewItem *)collectionView:itemForRepresentedObjectAtIndexPath: method, I call:
NSCollectionViewItem* newCollectionViewItem = [imageCollectionView makeItemWithIdentifier:#"Image"
forIndexPath:indexPath];
But this throws an exception and prints this to the console:
2016-12-19 17:51:27.463 MyApp[28177:3926764] -[NSNib _initWithNibNamed:bundle:options:] could not load the nibName: NSCollectionViewItem in bundle (null).
followed by a stack trace.
So how do I go about creating and using an NSCollectionViewItem that isn't subclassed or modified in any way?
Here is a very simple example which uses a Nib for the item's prototype:
#interface ViewController()
#property (weak) IBOutlet NSCollectionView *collectionView;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSNib *theNib = [[NSNib alloc] initWithNibNamed:#"Item" bundle:nil];
[self.collectionView registerNib:theNib forItemWithIdentifier:#"item"];
}
#pragma mark NSCollectionViewDataSource
- (NSInteger)numberOfSectionsInCollectionView:(NSCollectionView *)inCollectionView {
return 1;
}
- (NSInteger)collectionView:(NSCollectionView *)inCollectionView numberOfItemsInSection:(NSInteger)inSection {
return 10;
}
- (NSCollectionViewItem *)collectionView:(NSCollectionView *)inCollectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)inIndexPath {
NSCollectionViewItem *theItem = [inCollectionView makeItemWithIdentifier:#"item" forIndexPath:inIndexPath];
NSTextField *theLabel = (NSTextField *)theItem.view;
theLabel.stringValue = [NSString stringWithFormat:#"%d.%d", (int)inIndexPath.section, (int)inIndexPath.item];
return theItem;
}
#end
The NIB contains just a NSCollectionViewItem with a text field as view.
Addendum:
I think you should create a NSCollectionViewItem.xib for the registerClass variant. A view controller will search for a NIB with its class name, if you doesn't create its view manually in loadView. Thus, you can't use plain NSCollectionViewItem without a NIB for registering a class, because of makeItemWithIdentifier:forIndexPath: will access the view of the item.
I found a way to set up NSCollectionView without needing to add a .xib file.
The trick was inheriting from NSCollectionViewItem and using that subclass for -[NSCollectionView registerClass:forItemWithIdentifier:].
#import "ViewController.h"
#interface MyViewItem : NSCollectionViewItem
#end
#implementation MyViewItem {
}
- (instancetype)initWithNibName:(NSNibName)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nil bundle:nil];
NSButton *button = [[NSButton alloc] initWithFrame:NSZeroRect];
[button setTitle:#"Button"];
[self setView:button];
return self;
}
#end
#implementation ViewController {
IBOutlet NSCollectionView *_collectionView;
}
- (void)viewDidLoad {
[super viewDidLoad];
[_collectionView registerClass:[MyViewItem class]
forItemWithIdentifier:#"item"];
[_collectionView setDataSource:self];
}
- (NSInteger)collectionView:(NSCollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return 10;
}
- (NSCollectionViewItem *)collectionView:(NSCollectionView *)collectionView itemForRepresentedObjectAtIndexPath:(NSIndexPath *)indexPath {
return [_collectionView makeItemWithIdentifier:#"item" forIndexPath:indexPath];
}
#end

Populate NSTableView with a new object by clicking a button

Im trying to populate an NSTableView with a custom object by clicking a button. My custom class has just NSString properties: title and volume. I customized the init method to create an object and add it to my array that is hooked up to my table view. Then on the method for my button I had it create another object and add it to the array. When I run the program the object from the init method does display correctly. However, when I click my button I get nothing.
Here is the code for my header file:
#import <Cocoa/Cocoa.h>
#interface AppDelegate : NSObject <NSApplicationDelegate, NSTableViewDataSource>{
NSMutableArray *_myArray;}
#property (weak) IBOutlet NSTableView *tableView;
- (IBAction)button:(id)sender;
#end
and here is my implementation:
#import "AppDelegate.h"
#import "trade.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#end
#implementation AppDelegate
-(id)init{
self = [super init];
if (self){
_myArray = [[NSMutableArray alloc]init];
trade *firstTrade = [[trade alloc]init];
[firstTrade setTitle:#"Trade One"];
[firstTrade setVolume:#"Volume 01"];
[_myArray addObject:firstTrade];}
return self;}
- (IBAction)button:(id)sender {
trade *secondTrade = [[trade alloc]init];
[secondTrade setTitle:#"Trade two"];
[secondTrade setVolume:#"Volume 02"];
[_myArray addObject:secondTrade];
[_tableView reloadData];}
-(NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return _myArray.count;}
-(id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row{
if ([tableColumn.identifier isEqualToString:#"Title"]){
trade *item = [_myArray objectAtIndex:row];
return item.title;
}else{
trade *item = [_myArray objectAtIndex:row];
return item.volume;}}
#end
Not sure what I'm doing wrong here as what I did in the init method is pretty much the same thing I did in button method. Any help is greatly appreciated. Here is a picture of the program after I run it:
tableView program
As you can see my first object appears in the table view, but not the second.
While looking at this project I duplicated the [_tableView reloadData]; line and placed a breakpoint on the second one so I could see what was going on right after the first one is called. One thing I noticed is that _myArray does now contain 2 objects after the button click.
However, when I look into _tableView it shows that _myArray only contains 1 object. How is it that the object is actually getting added but the table view is only getting 1?
Here is a picture for reference:Debug

Taking contact information and putting it into a UITableView

I am creating an app where you press a button and it opens up your contacts list. You can then select the contact you want to add and it imports their name and email into the app. I currently have that information going into labels but I want to add it to a table view cell. How would I do this?
My Code:
.h:
#import <UIKit/UIKit.h>
#import <AddressBookUI/AddressBookUI.h>
#interface FirstViewController : UIViewController <ABPeoplePickerNavigationControllerDelegate>
- (IBAction)showPicker:(id)sender;
#property (weak, nonatomic) IBOutlet UILabel *firstName;
#property (weak, nonatomic) IBOutlet UILabel *email;
#end
.m:
#import "FirstViewController.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
#synthesize firstName;
#synthesize email;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)showPicker:(id)sender {
ABPeoplePickerNavigationController *picker =
[[ABPeoplePickerNavigationController alloc] init];
picker.peoplePickerDelegate = self;
[self presentModalViewController:picker animated:YES];
}
- (void)peoplePickerNavigationControllerDidCancel:
(ABPeoplePickerNavigationController *)peoplePicker
{
[self dismissModalViewControllerAnimated:YES];
}
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person {
[self displayPerson:person];
[self dismissModalViewControllerAnimated:YES];
return NO;
}
- (BOOL)peoplePickerNavigationController:
(ABPeoplePickerNavigationController *)peoplePicker
shouldContinueAfterSelectingPerson:(ABRecordRef)person
property:(ABPropertyID)property
identifier:(ABMultiValueIdentifier)identifier
{
return NO;
}
- (void)displayPerson:(ABRecordRef)person
{
NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
kABPersonFirstNameProperty);
self.firstName.text = name;
ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);
NSString *emailId = (__bridge NSString *)ABMultiValueCopyValueAtIndex(emails, 0);//0 for "Home Email" and 1 for "Work Email".
self.email.text = emailId;
}
#end
OK, I am going to explain how you programmatically implement a very basic table view controller. It will be up to you, though, to figure out how to integrate this into your application.
Let's start with the header file, let's call it MyTableViewController.h:
#interface MyTableViewController : UIViewController <UITableViewDelegate, UITableViewDataSource>
{
}
#end
As you can see, your controller class adopts the protocols UITableViewDelegate and UITableViewDataSource.
Now let's look at a first snippet from the implementation file MyTableViewController.m. Your first job, obviously, is to create the controller's view. You do this in your controller's loadView method. If you want to learn more about the view life cycle and how to program a UIViewController I suggest you read the UIViewController class reference and the accompanying View Controller Programming Guide.
- (void) loadView
{
// Give the view some more or less arbitrary initial size. It will be
// resized later when it is actually displayed
CGRect tableViewFrame = CGRectMake(0, 0, 320, 200);
UITableView* tableView = [[[UITableView alloc] initWithFrame:tableViewFrame style:UITableViewStyleGrouped] autorelease];
self.view = tableView;
// Here we make sure that the table view will take as much horizontal
// and vertical space as it can get when it is resized.
UIViewAutoresizing autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
tableView.autoresizingMask = autoresizingMask;
// We need to tell the table view that we are both its delegate and
// its data source.
tableView.delegate = self;
tableView.dataSource = self;
}
Just to let you know: You can omit loadView entirely if your controller is a subclass of UITableViewController, but I deliberately do not take that shortcut so that I can show you how a table view needs a delegate and a data source. Most important ist the data source.
In the next snippet in MyTableViewController.m we are going to implement some basic UITableViewDataSource methods. For this you need to understand how a table view is structured: A table view is divided into sections, and each section has a number of cells. The point of having sections is to visually separate groups of cells, with an optional section header or footer. I am not going into details here, though, to keep this simple.
- (NSInteger) numberOfSectionsInTableView:(UITableView*)tableView
{
// Let's keep it simple: We want just one section
return 1;
}
- (NSInteger) tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section
{
// Let's keep it simple: We want just one row, or table view cell.
// Since we only have one section (see above) we don't have to look
// at the section parameter.
return 1;
}
And now, finally, the centerpiece where you create your table view cell. Again, this is a UITableViewDataSource method that we implement. Note that we do not need to inspect the indexPath parameter only because we know that we only have one section and one row. In a real world application you will probably have to write switch-case or if-else statements that examine indexPath.section and indexPath.row so that you can distinguish between the different cells you need to create.
- (UITableViewCell*) tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath
{
// This is very important for your future table view implementations:
// Always ask the table view first if it already has a cell in its
// cache. If you don't do this your table view will become slow when
// it has many cells.
NSString* identifier = #"MyTableViewCell";
UITableViewCell* cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (cell == nil)
{
// Aha, the table view didn't have a cell in its cache, so we must
// create a new one. We use UITableViewCellStyleValue1 so that the
// cell can display two pieces of information.
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier] autorelease];
}
// Regardless of whether we got the cell from the table view's cache
// or create a new cell, we must now fill it with content.
// First, obtain the information about the person from somewhere...
NSString* personName = ...;
NSString* personEmail = ...;
// ... then add the information to the table cell
cell.textLabel.text = personName;
cell.detailTextLabel.text = personEmail;
return cell;
}
As a final nicety, we implement a UITableViewDelegate method:
- (void) tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:NO];
// Here you can react to the user tapping on the cell. If you
// don't want the user to be able to select a cell you can
// add the following line to tableView:cellForRowAtIndexPath:
// cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
It is difficult to tell how you should integrate this into your application. It all depends where you want to display the table view. Since you say you want to replace the two labels you already have, one possible approach could be this:
In Interface Builder, add the table view as a subview to the main view of your FirstViewController
Add an outlet to FirstViewController that you connect to the table view
Let FirstViewController adopt the protocols UITableViewDelegate and UITableViewDataSource
Connect FirstViewController to the delegate and data source outlets of the table view
Don't implement loadView from my example, you don't need it, you already have made all the connections etc. in Interface Builder
If you need further help with integration, I suggest that you ask a new question and possibly refer to this answer. Good luck.

NSMutableArray Returns NULL

I try adding objects to NSMutableArray from another class (secondViewController) and then add it to my UITableView in my FirstViewController, but it returns null when I print it using NSLog. Here is my set up.
FirstViewController.h:
#interface FirstViewController : UIViewController <UITableViewDelegate,UITableViewDataSource>{
IBOutlet UITableView *mytableview;
NSMutableArray *mytableinfo;
}
#property (nonatomic,retain) IBOutlet UITableView *mytableview;
#property (retain) IBOutlet NSMutableArray *mytableinfo;
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#synthesize mytableinfo,mytableview;
-(IBAction)addShift:(id)sender{
SecondViewController *secondViewController = [[SecondViewController alloc]init];
[self presentModalViewController:secondViewController animated:YES];
}
- (void)viewDidLoad
{
mytableinfo = [[NSMutableArray alloc]init];
[super viewDidLoad];
}
SecondViewController.m
#import "SecondViewController.h"
#import "FirstViewController.h"
#implementation SecondViewController
#synthesize dateformatter,mydatepicker,startingTime;
-(IBAction)saveShift:(id)sender{
FirstViewController *firstViewController = [[FirstViewController alloc]init];
[firstViewController.mytableinfo addObject:#"Hello world"];
NSLog(#"%#",firstViewController.mytableinfo);
[self dismissModalViewControllerAnimated:YES];
}
My goal is to ultimately feed a mytableviewfrom mytableinfo. I'm not even sure if this is the best way to go about it. Any advice would be appreciated.
In SecondViewController, you are creating a FirstViewController with alloc init. At that point, mytableinfo on FirstViewController is nil because you don't allocate until viewDidLoad.
What loads SecondViewController? Because you're dismissing it modally. If it's FirstViewController, then when you alloc init first view controller, you're not calling the instance that presented it modally.
It's also not very MVC to have one view poke at another like that. It creates code that's couple at the view layer and modifying data at the view layer. It is better to create a model and have both views modifying that model.
How to create a NSMutable Array which can access from different view controllers
Another way to communicate between views is for one view to pass a delegate (a callback) to the other view. That allows the other view to not be coupled to the other view - it only knows about the protocol for the delegate.
What exactly does delegate do in xcode ios project?
There is a point that look strange to me in your "SecondViewController" you dissmiss it like it's a modal.
My Question is then... who started the modal presentation?
A "FirstViewController"? If it's the case, why are you creating a new one, on dismissing the second, the First that launched it will resume it's activity.
An other thing that I don't understand is that the designated initializer for a UIViewController is
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
You can pass nil to both argument, if no nib need to be associated with.
And finaly, if you need to get back a NSMutableArray to a 1st ViewController (VC) from a 2nd VC that was modally presented by the 1st you can do this in the 2nd VC:
- (id)initWithMutableArray:(NSMutableArray *)theArray {
//... put standard init code here }
And make that the default initializer of your second VC. But this make sense only if 2nd VC absolutely need a mutable array.
And now for my curiosity because I don't understand this line
#property (retain) IBOutlet NSMutableArray *mytableinfo;
Why is this an IBOutlet? That look like a potential source of problem.
IBOutlet are usually pointers to UI elements in a xib file.
When populating a UITableView with an array that can be modified by multiple modal views during the course of your app, I find one of the best ways to do this is with NSUserDefaults. You can create an NSUserDefaults object for reference like this:
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
Then you can assign objects to each key in defaults, which is really just a plist (which is just a list of keys with objects associated with them.
So then, when you want to store the array in defaults, you can say:
[defaults setObject:mytableinfo forKey:#"tableInformationKey"];
Then, whenever you want to access that data, you can say:
NSMutableArray* tableInfoCopy = [defaults mutableArrayValueForKey:#"tableInformationKey"];
That will make you a copy of the array you have stored in NSUserDefaults (NSUserDefaults can be accessed from anywhere in your app), so then you can make changes to that mutable array you just made. Once you are done making changes, you can reassign it to NSUserDefaults like this:
[defaults setObject:tableInfoCopy forKey#"tableInformationKey"];
So when you populate your UITableView, in
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
put something like:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Foobar"];
if (cell == nil) {
// No cell to reuse => create a new one
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"Foobar"] autorelease];
// Initialize cell with some customization
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
cell.textLabel.textColor = [UIColor blackColor];
}
NSArray* arrayOne = [defaults objectForKey:#"tableInformationKey"];
NSString* title = [arrayTwo objectAtIndex:indexPath.row];
//this goes to the index in the array of whatever cell you are
// at, which will populate your table view with the contents of this array (assuming the array contains strings)
// Customize cell
cell.textLabel.font = [UIFont fontWithName:#"Helvetica" size:25];
return cell;
}
Use them the easiest way is to put the array in your AppDelegate
// populate appDelegate's array
AppDelegate *appDelegate = (myAppDelegate *) [[UIApplication sharedApplication] delegate];
[appDelegate.arrayMyTableInfo addObject:#"HelloWorld"];
Here is how you can do what I've suggested :
(This is part of your code updated)
This is in your secondView, this is one of many way to pass the array to your second view.
#synthesize array4Test;
- (id)initWithMutableArray:aMutableArray
{
self = [self initWithNibName:nil bundle:nil];
if (self)
{
self.array4Test = aMutableArray;
}
return self;
}
- (void)dealloc
{
// HERE clean up the property is set to retain.
self.array4Test = nil;
[super dealloc];
}
Here is the code for the firstView
-(IBAction)addShift:(id)sender{
SecondViewController *secondViewController = [[SecondViewController alloc] initWithMutableArray:self.mytableinfo];
[self presentModalViewController:secondViewController animated:YES];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[self.mytableview reloadData];
NSString *aString = [mytableinfo lastObject];
if (aString)
{
NSLog(#"This just came back from the second View\n%#", aString);
}
}

NSTableView binding problem

I have only just started with XCode (v3.2.2) and Interface Builder and have run into a problem.
Here is what I have done:
I have made a class to be the datasource of a NSTableView:
#interface TimeObjectsDS : NSControl {
IBOutlet NSTableView * idTableView;
NSMutableArray * timeObjects;
}
#property (assign) NSMutableArray * timeObjects;
#property (assign) NSTableView * idTableView;
- (id) init;
- (void) dealloc;
- (void) addTimeObject: (TimeObj *)timeObject;
// NSTableViewDataSource Protocol functions
- (int)numberOfRowsInTableView:(NSTableView *)tableView;
- (id)tableView:(NSTableView *)tableView
objectValueForTableColumn:(NSTableColumn *)tableColumn row:
(int)row;
#implementation TimeObjectsDS
#synthesize timeObjects;
#synthesize idTableView;
-(id) init {
if (self = [super init]) {
self.timeObjects = [[NSMutableArray alloc] init];
TimeObj *timeObject = [[TimeObj alloc] init];
[timeObject setProjectId:11];
[timeObject setDescription:#"Heja"];
[timeObject setRegDate:#"20100331"];
[timeObject setTimeSum:20.0];
[timeObjects addObject:timeObject];
[timeObject release];
[idTableView reloadData];
}
return self;
}
- (void) dealloc {
[idTableView release];
[timeObjects release];
[super dealloc];
}
// Functions
- (void) addTimeObject: (TimeObj *)timeObject {
[self.timeObjects addObject:timeObject];
[idTableView reloadData];
}
// NSTableViewDataSource Protocol functions
- (int) numberOfRowsInTableView:(NSTableView *)tableView {
return [self.timeObjects count];
}
- (id) tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row {
return [[timeObjects objectAtIndex:row] description];
}
#end
I have then bound my NSTableView in the View to this datasource like so:
alt text http://www.og-entertainment.com/tmp/ib_datasource_bindings_big.png
I have also bound the View NSTableView to the Controller idTableView variable in Interface Builder seen above
In the init function I add a element to the mutable array. This is displayed correctly in the NSTableView when I run the application. However when I add another element to the array (of same type as in init) and try to call [idTableView reloadData] on the View nothing happens.
In fact the Controller idTableView is null. When printing the variable with NSLog(#"idTableView: %#", idTableView) I get "idTableView: (null)"
Im runing out of ideas how to fix this. Any ideas to what I could do to fix the binding?
If your tableview outlet in your controller is null, then you haven't connected it in Interface Builder. Your screenshot above shows a connection to TimeObjectsDS, but that doesn't mean a lot - is that the instance that you are calling reloadData from? It is possible that you have more than one instance of this class, for example.
That's just one possibility. Without more code, it's not feasible to list many more.
Incidentally, in MVC it's considered a bad thing to connect a model object directly to a view. You may just be using the terminology incorrectly.