I have a small OS X test project written in Objective-C using storyboards with XCode 6.2, the goal of which is to test the binding of an NSArray to a View-based NSTableView. Although this area has been beaten to death online, I cannot for some reason make my binding work.
I have defined a simple object TESTPerson which has been sub-classed from NSObject as follows:
// TESTPerson.h
// TBLViewBindingTest
#import <Foundation/Foundation.h>
@interface TESTPerson : NSObject
@property (nonatomic,strong) NSString *strFirstName;
@property (nonatomic,strong) NSString *strLastName;
@end
#import "TESTPerson.h"
@implementation TESTPerson
-(instancetype)init
{
if(!self)
{
self = [super init];
}
_strFirstName = @"First Name Test";
_strLastName = @"Last Name Test";
return self;
}
@end
I dropped a NSTableView into the view provided by the Storyboard, then dropped a NSArrayController into the View Controller scene.
I create and attach IBOutlets for the NSTableView and NSArrayController instances in ViewController.h. NSArray *arrayNames is also declared and will be used as the content source by the NSArrayController.
// ViewController.h
// TBLViewBindingTest
#import <Cocoa/Cocoa.h>
#import "TESTPerson.h"
@interface ViewController : NSViewController
@property (strong) IBOutlet NSTableView *myTableView;
@property (nonatomic,strong) NSArray *arrayNames;
@property (strong) IBOutlet NSArrayController *myArrayController;
@end
viewDidLoad in ViewController.m is updated to create two instances of TESTPerson, which are then added to the _arrayNames property.
// ViewController.m
// TBLViewBindingTest
#import "ViewController.h"
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
TESTPerson *p = [[TESTPerson alloc]init];
TESTPerson *p1 = [[TESTPerson alloc]init];
_arrayNames = [[NSArray alloc]initWithObjects:p,p1, nil];
}
- (void)setRepresentedObject:(id)representedObject
{
[super setRepresentedObject:representedObject];
}
@end
I selected the ArrayController in the Storyboard and set the Class Name in the Attributes tab to 'TESTPerson', and set the Bindings tab to bind the ArrayController with my ViewController using a Model Key Path of arrayNames. It is my expectation that arrayNames will be populated with the two TESTPerson instances created in the ViewController viewDidLoad method.
I then selected the Table View in the Storyboard and set its Table Content to bind to the Array Controller using a Controller Key of arrangedObjects.
Drilling down into the TableView hierarchy I selected the Table View Cell node for each column and bound the Value to Table Cell View with Model Key Paths of objectValue.strFirstName and objectValue.strLastName respectively.
My understanding is this is all that is required in order to present data from my array in the tableview. When I execute the program however, no table rows are displayed. I did a dump of the ArrayController content via NSLog by adding a button / method:
NSLog(@"%@",[_myArrayController content]);
shows me that _myArrayController does not have any content:
`2015-03-22 13:48:49.379 TBLViewBindingTest[48776:4766635] (
)`
I double-checked that the NSArrayController in the View Controller Scene is bound to IBOutlet _myArrayController (it was).
I then added a line of code in viewDidLoad to see if I could force something into the _myArrayController:
[_myArrayController addObjects:_arrayNames];
NSLog(@"%@",[_myArrayController content]);
results in a populated tableView on the screen and objects in _myArrayController:
2015-03-22 13:50:28.240 TBLViewBindingTest[48807:4768827] (
"<TESTPerson: 0x610000024ec0>",
"<TESTPerson: 0x610000024ee0>",
"<TESTPerson: 0x610000024ec0>",
"<TESTPerson: 0x610000024ee0>"
)
To me it appears that the binding between the ArrayController instance and _arrayNames is not accepted. I have tried many things - adding the TESTPerson properties as keys in the ArrayController Attributes tab etc, but to no avail. Using NSObject as the base for TESTPerson should be enough to make the TESTPerson class KVC compliant(?), but I am wondering if the ArrayController does not agree?
As far as I can tell, everything that needs to be in place for basic data display is there. What have I missed?