How does the NSTableView set content Mode(view-based or cell-based) by code? - cocoa

As title.
How does the NSTableView set content Mode(view-based or cell-based) by code?
Thanks for helping

NSTableView defaults to being cell-based, which makes sense for backwards compatibility. Table views are view-based when the table view delegate implements -tableView:viewForTableColumn:row:. You can easily test by programmatically creating a table view as follows:
#implementation BAVAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSView *contentView = self.window.contentView;
NSTableView *tableView = [[NSTableView alloc] initWithFrame:(NSRect){{50, NSMaxY(contentView.frame) - 200}, {400, 200}}];
tableView.dataSource = self;
tableView.delegate = self;
[contentView addSubview:tableView];
NSTableColumn *column = [[NSTableColumn alloc] initWithIdentifier:#"column"];
column.width = 400;
[tableView addTableColumn:column];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return 3;
}
- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
return [NSString stringWithFormat:#"%ld", row];
}
//- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
// NSTextField *textField = [[NSTextField alloc] initWithFrame:(NSRect){.size = {100, 15}}];
// textField.stringValue = [NSString stringWithFormat:#"%ld", row];
// return textField;
//}
#end
If you run this code with that delegate method commented out, you get a cell-based table view:
And if you uncomment that delegate method, you get a view-based table view:
The documentation for -tableView:viewForTableColumn:row: states that
This method is required if you wish to use NSView objects instead of NSCell objects for the cells within a table view. Cells and views can not be mixed within the same table view.
which hints at it being the condition that determines whether a table view is cell- or view-based.

Related

UIAccessibility is not selecting correct elements

I have several UIWindows in my app. Some UIWindows have very high window levels. i.e.
window.windowLevel = currentWindowLevel+1;
For some reason when turning on accessibility support, the system insists on reading out the accessibility labels of views located in the lower level window, even in cases where the views aren't even visible.
This minimal example exemplifies this behavior.
With accessibility support turned on, try to press the label in the red window. The system will read out the text from the underneath table view instead
#interface ViewController () <UITableViewDataSource>
#property (weak, nonatomic) IBOutlet UITableView *tableview;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.tableview.dataSource = self;
[self.tableview registerClass:[UITableViewCell class] forCellReuseIdentifier:#"cell"];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIWindow *w = [[UIWindow alloc] initWithFrame:self.view.bounds];
w.windowLevel = self.view.window.windowLevel + 1;
w.backgroundColor = [UIColor redColor];
w.hidden = NO;
w.isAccessibilityElement = YES;
UILabel *l = [[UILabel alloc] init];
l.text = #"KUKUKUKUKUKUKUKLU";
[l sizeToFit];
l.frame = CGRectOffset(l.frame, 40, 100);
[w addSubview:l];
w.accessibilityLabel = #"Read this outloud instead";
static id window;
window = w;
});
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 100;
}
// Row display. Implementers should *always* try to reuse cells by setting each cell's reuseIdentifier and querying for available reusable cells with dequeueReusableCellWithIdentifier:
// Cell gets various attributes set automatically based on table (separators) and data source (accessory views, editing controls)
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.textLabel.text = #"Test";
return cell;
}
#end
Solution is to set the attribute
Window.accessibilityViewIsModal = YES;

BackgroundColor doesn't work in NSTableCellView

Why the backgroundColor doesn't work with owner:self.table? It only works with owner:self, however, with the second option -awakeFromNib is called many times.
setStringValue works with both options.
- (id)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
NSTableCellView *cell = [tableView makeViewWithIdentifier:#"MainCell" owner:self.table];
[cell.textField setStringValue:#"FunWithFlags"]
cell.layer.backgroundColor = [[NSColor greenColor] CGColor];
return cell;
}
The owner param expects the owner object of the NIB which should be loaded and instantiated to create a new view with the supplied identifier.
The table object self.table is not the owner of any nib hence it does not return any view.

UITableView Segue

Im trying to make a small project. Could someone help me understand why the segue does not work?
#import "CarTableViewController.h"
#import "CarTableViewCell.h"
#import "CarDetailViewController.h"
#interface CarTableViewController ()
#end
#implementation CarTableViewController
#synthesize carMakes = _carMakes;
#synthesize carModels = _carModels;
#synthesize carImages = _carImages;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.carMakes = [[NSArray alloc]
initWithObjects:#"Chevy",
#"BMW",
#"Toyota",
#"Volvo",
#"Smart", nil];
self.carModels = [[NSArray alloc]
initWithObjects:#"Volt",
#"Mini",
#"Venza",
#"S60",
#"Fortwo", nil];
self.carImages = [[NSArray alloc]
initWithObjects:#"chevy_volt.jpg",
#"mini_clubman.jpg",
#"toyota_venza.jpg",
#"volvo_s60.jpg",
#"smart_fortwo.jpg", nil];
// Uncomment the following line to preserve selection between presentations.
// self.clearsSelectionOnViewWillAppear = NO;
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return _carModels.count;
}
#pragma mark - Table view data source
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"carTableCell";
CarTableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[CarTableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.makeLabel.text = [self.carMakes
objectAtIndex: [indexPath row]];
cell.modelLabel.text = [self.carModels
objectAtIndex:[indexPath row]];
UIImage *carPhoto = [UIImage imageNamed:
[self.carImages objectAtIndex: [indexPath row]]];
cell.carImage.image = carPhoto;
return cell;
}
The code work´s fine, and loads a tableView, but I need to go to CarDetailViewControler and I´m using the following code, but it does not work.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowCarDetails"])
{
CarDetailViewController *detailViewController =
[segue destinationViewController];
NSIndexPath *myIndexPath = [self.tableView
indexPathForSelectedRow];
detailViewController.carDetailModel = [[NSArray alloc]
initWithObjects: [self.carMakes
objectAtIndex:[myIndexPath row]],
[self.carModels objectAtIndex:[myIndexPath row]],
[self.carImages objectAtIndex:[myIndexPath row]],
nil];
}
}
In the storyboard did you use a cell prototype? If so, did you control-drag from the prototype to the destination viewcontroller and create the named segue?
The method you are using requires the segue to be defined completely in the storyboard, meaning the trigger for the segue is tied to the cell prototype.
You can manually trigger a segue using:
[self performSegueWithIdentifier:#"ShowCarDetails" sender:self];
in your:
tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath as an alternative.

Cocoa : Custom TableView cell?

I am not really familiar with tables, as I usually make games, but now I want to create a level builder where I need a table view with custom cells. I have created a nib file and I have subclassed NSTableCellView, but I don't know what to do next. All I have is:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification{
NSScrollView * tableContainer = [[NSScrollView alloc] initWithFrame:NSMakeRect(self.window.frame.size.width-TABLEWIDTH, 0, TABLEWIDTH, self.window.frame.size.height)];
SpriteTable *sT = [[SpriteTable alloc]initWithFrame:NSMakeRect(self.window.frame.size.width-TABLEWIDTH, 0, TABLEWIDTH, self.window.frame.size.height)];
NSTableView *tableView = [[NSTableView alloc] initWithFrame: sT.bounds];
NSTableColumn* firstColumn = [[[NSTableColumn alloc] initWithIdentifier:#"firstColumn"] autorelease];
[[firstColumn headerCell] setStringValue:#"First Column"];
[tableView addTableColumn:firstColumn];
tableView.dataSource = self;
tableView.delegate = self;
[tableContainer setDocumentView:tableView];
tableContainer.autoresizingMask = NSViewHeightSizable | NSViewMinXMargin;
[self.window.contentView addSubview: tableContainer];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView{
return 4;
}
- (NSView *)tableView:(NSTableView *)tableView
viewForTableColumn:(NSTableColumn *)tableColumn
row:(NSInteger)row {
// get an existing cell with the MyView identifier if it exists
CustomCell *result = [tableView makeViewWithIdentifier:#"MyView" owner:self];
// There is no existing cell to reuse so we will create a new one
if (result == nil) {
NSLog(#"result = nil");
// create the new NSTextField with a frame of the {0,0} with the width of the table
// note that the height of the frame is not really relevant, the row-height will modify the height
// the new text field is then returned as an autoreleased object
//result = [[[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 250, 70)] autorelease];
// the identifier of the NSTextField instance is set to MyView. This
// allows it to be re-used
result.identifier = #"MyView";
}
// result is now guaranteed to be valid, either as a re-used cell
// or as a new cell, so set the stringValue of the cell to the
// nameArray value at row
result.imageView.image = [NSImage imageNamed:NSImageNameHomeTemplate];
// return the result.
return result;
}
If any, which delegate methods do I have to implement ? And how do I customize my cell WITH a nib file ?
Do this in ur subview->
#implementation suhasView
#synthesize name,containerView;// container view contains ur subview
- (NSView*) myView
{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSNib *theNib = [[NSNib alloc] initWithNibNamed:#"suhas"bundle:bundle];
[theNib instantiateNibWithOwner:self topLevelObjects:nil];
return containerView;
}
In Controller->
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
suhas *a=[[suhas alloc]initWithFrame:NSMakeRect(0,0, 40, 40)];
NSView * v = [a myView];
[a.name setStringValue:#"suhas"];
return v;
}...//sorry for my naming of the class:)

Using segues to display a UIView from UITableViewController

I am trying to connect a UITableViewController to a UIView using storyboards. I have a TabBarController that connects to a Navigation Controller that displays a UITableViewController, displaying a small array. I want to click on a row and that trigger a simple UIView with a label, still displayed in the UINavigationController so I can navigate back to the UITableViewController
I can get the UITableViewController to display OK, with the array, but I can't get the row to trigger when I select it.
This is my UITableViewController (AtoZController.m) file:
#import "AtoZController.h"
#import "StoreDetailsView.h"
#interface AtoZController ()
#end
#implementation AtoZController
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedString(#"A to Z", #"An A to Z List of Stores");
AtoZArray = [[NSMutableArray alloc] init];
[AtoZArray addObject:#"Apple"];
[AtoZArray addObject:#"Boots"];
[AtoZArray addObject:#"Topman"];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
} else {
return YES;
}
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [AtoZArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
NSInteger row = [indexPath row];
cell.textLabel.text = [AtoZArray objectAtIndex:row];
return cell;
}
I have a segue connected, named storeDetailsSegue, from the UITableViewController to a UIView. I am attempting to use the prepareForSeque method to trigger the next view but have had no luck with the following code.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
StoreDetailsView *detail = [self detailForIndexPath:path];
[segue.destinationViewController setDetail:detail];
}
As it keeps saying there is an error as there is 'No visible #interface for "AtoZController declares the selector 'detailForIndexPath'". I may be doing something completely wrong as I have never used storyboards before. What I want is for a simple UIView to display a label that dynamically changes to display the row number that has been selected.
I don't know if the UITableViewController should infact be a UITableView but as I have never used segues or storyboards I have no idea what could be causing the problem.
Any advice at all would be greatly appreciated.
UPDATE:
So I managed to get the UIViewController to display but still can't get the label to update before I display the view.

Resources