Search code examples
cocoanstableviewosx-yosemitensstoryboard

Setting dataSource for NSTableView across scenes in a storyboard


I am using XCode 6 on OS X 10.10 and have a storyboard containing a window with a split view controller, as shown in the following image.

My storyboard

The split view controller (highlighted in the image) is an instance of MyViewController, which has the following code:

MyViewController.h

#import <Cocoa/Cocoa.h>

@interface MyViewController : NSSplitViewController <NSTableViewDataSource>

@end

MyViewController.m

#import "MyViewController.h"

@implementation MyViewController

- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
    return 7;
}

- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
    return [NSString stringWithFormat:@"%ld", (long)row];
}

@end

I would like to make the view controller the dataSource of the NSTableView in my storyboard, however I am unable to connect them. Is there a reason for this?


Solution

  • In your NSSplitViewController-subclass viewDidLoad-method set the data source programmatically. You need to implement the child view controller class as well (with the tableView outlet connected to the control).

    MySplitViewController.m

    - (void)viewDidLoad
    {
      [super viewDidLoad];
      for (NSSplitViewItem *item in self.splitViewItems)
      {
        NSViewController *controller = item.viewController;
        if ([controller isKindOfClass:[MyChildController class]])
        {
           MyChildController *myController = (MyChildController *)controller;
           myController.tableView.dataSource = self;
           [myController.tableView reloadData];
        }
      }
    }
    

    But to tell you the truth I don't like this approach. It's more better when the table view's data source methods are in the native view controller class.

    Another way to do that. MyChildController.h file:

    @class MyChildViewController;
    @protocol MyChildControllerDelegate <NSObject>
    
    - (void)childController:(MyChildViewController *)controller didSelectRowAtIndex:(NSUInteger)index;
    
    @end
    
    @interface MyChildViewController : NSViewController <NSTableViewDataSource, NSTableViewDelegate>
    
    @property (nonatomic, weak) id<MyChildControllerDelegate> delegate;
    
    @property (nonatomic, retain) NSArray *items;
    
    @property (nonatomic, weak) IBOutlet NSTableView *tableView;
    
    @end
    

    Don't forget to implement all the table view dataSource and delegate methods you need. MySplitViewController.m file:

    - (void)viewDidLoad
    {
      [super viewDidLoad];
      for (NSSplitViewItem *item in self.splitViewItems)
      {
        NSViewController *controller = item.viewController;
        if ([controller isKindOfClass:[MyChildController class]])
        {
           MyChildController *myController = (MyChildController *)controller;
           myController.delegate = self;
           [myController setItems:_items];
        }
      }
    }