Setting a NSString to the sending end of a segue - iphone

I made a simple project to explain my problem. Basically what I did was make a project with the templet of a Master Detail Application. Then in the
DetailViewController.h
nothing
DetailViewController.m
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"showDetail"])
{
[segue.destinationViewController setCellName2:#"New String"];
}
}
MasterViewController.h
#property(nonatomic,strong) NSString *cellName2;
MasterViewController.m
#synthesize cellName2;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(#"%#", cellName2);
}
My problem is in the detailViewController where I set the cellName2, I cant set it because the detailViewController is the receivingViewController of the segue. Is their a method to set the sendingViewController end of a segue?
Edit
After Firo's answer my code looks like this now
MasterViewContoller.h
#import <UIKit/UIKit.h>
#import "DetailViewController.h"
#interface MasterViewController : UITableViewController <DetailViewDelegate>
#property(nonatomic,strong) NSString *cellName2;
#end
.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#interface MasterViewController () {
NSMutableArray *_objects;
}
#end
#implementation MasterViewController
#synthesize cellName2;
- (void)awakeFromNib
{
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.navigationItem.leftBarButtonItem = self.editButtonItem;
UIBarButtonItem *addButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:#selector(insertNewObject:)];
self.navigationItem.rightBarButtonItem = addButton;
self.cellName2 = cellName;
NSLog(#"%#", self.cellName2);
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)insertNewObject:(id)sender
{
if (!_objects) {
_objects = [[NSMutableArray alloc] init];
}
[_objects insertObject:[NSDate date] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _objects.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDate *object = _objects[indexPath.row];
cell.textLabel.text = [object description];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_objects removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"showDetail"]) {
/* assigning self as delegate, telling the detail view that I implement
* setCellName2:, so it (the detailVC) can call it whenever it wants to.
*/
[segue.destinationViewController setDelegate:self];
}
}
// my implementation of the DetailViewDelegate protocol that I abide to
/* note: #pragma mark is not required, just for comment, documentation
* and find-ability purposes
*/
//#pragma mark - DetailViewDelegate
// note: this is just a property setter so this is not actually needed
//- (void)setCellName2:(NSString *)cellName {
// self.cellName2 = cellName;
// NSLog(#"%#", self.cellName2);
//}
#end
DetailViewContoller.h
#import <UIKit/UIKit.h>
/* defining a protocol, whoever is a DetailViewDelegate must implement my
* defined methods
*/
#protocol DetailViewDelegate <NSObject>
- (void)setCellName2:(NSString *)cellName;
#end
#interface DetailViewController : UIViewController
/* storing a delegate property. Whoever sets themselves to my delegate
* must implement my DetailViewDelegate's methods (setCellName2: in this case)
*/
#property (weak, nonatomic) id<DetailViewDelegate> delegate;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
.m
#import "DetailViewController.h"
#interface DetailViewController ()
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//[self.delegate setCellName2:#""];
[self configureView];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"showDetaila"])
{
[segue.destinationViewController setCellName2:#"New String"];
}
}
#end
The problem now is, i am getting the error "Use of undeclared identifier 'cellName'; did you mean 'cellName2'?"

You are looking for delegates and protocols. Since you are not segueing from your detailVC to your masterVC you cannot put this setter in prepareForSegue. You need to store a reference to the master and have callbacks to it. Here is how you would do it with your basic example:
DetailViewController.h
/* defining a protocol, whoever is a DetailViewDelegate must implement my
* defined methods
*/
#protocol DetailViewDelegate <NSObject>
- (void)setCellName2:(NSString *)cellName;
#end
#interface DetailViewController : UIViewController
/* storing a delegate property. Whoever sets themselves to my delegate
* must implement my DetailViewDelegate's methods (setCellName2: in this case)
*/
#property (weak, nonatomic) id<DetailViewDelegate> delegate;
#end
DetailViewController.m
#implementation DetailViewController
// some action or method
- (IBAction)buttonPress:(id)sender {
// look below at Master's prepareForSegue
/* calling the method that my delegate implements, my delegate can be any
* object that implements my protocol (DetailViewDelegate)
*/
[self.delegate setCellName2:#""];
}
#end
MasterViewController.h
#import "DetailViewController.h"
// saying I implement the DetailViewDelegate protocol (and all necessary methods)
#interface MastViewController : UITableViewController <DetailViewDelegate>
#end
MasterViewController.m
#interface MasterViewController ()
#property(strong, nonatomic) NSString *cellName2;
#end
#implementation MasterViewController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"showDetail"]) {
/* assigning self as delegate, telling the detail view that I implement
* setCellName2:, so it (the detailVC) can call it whenever it wants to.
*/
[segue.destinationViewController setDelegate:self];
}
}
// my implementation of the DetailViewDelegate protocol that I abide to
/* note: #pragma mark is not required, just for comment, documentation
* and find-ability purposes
*/
#pragma mark - DetailViewDelegate
// note: this is just a property setter so this is not actually needed
- (void)setCellName2:(NSString *)cellName {
_cellName = cellName
NSLog("%#", self.cellName);
}
#end
I would give you some more information about delegates and protocols but it is an extremely common pattern when dealing with iOS development. You also should become extremely familiar with delegates and protocols, you will find it useful in many situations and it will help you better understand iOS development and make you a more competent programmer. If something does not work (or make sense) let me know. I just typed this up in SO so there could be some mild mistakes.
Edit
Note: If this becomes to far from the original question you may need to just create a new one.
Your main issue here is that you have self.cellName2 = cellName; in your MasterViewController. According to your original post you want the DetailVC to set this, right? So it will need to go into DetailViewController's viewDidLoad:
- (void)viewDidLoad {
[super viewDidLoad];
[self.delegate setCellName2:#"My custom text!"];
}
Then remove:
self.cellName2 = cellName;
NSLog(#"%#", self.cellName2);
From your MasterViewController's viewDidLoad. Your error is with the first line there (I am assuming). What is cellName? It is not a string and you have not defined it as a variable or property, hence the error.

Are you sure that the code is in the right class? And that you have the segues hooked up correctly in the storyboard?
In your DetailViewController code, you indicate that the segue identifier is "showDetail". It would seem to me that you ought to be handling that in your MasterViewController, as the pattern is typically that MasterViewController is responsible for seguing to the DetailViewController for the purpose of showing details.
Basically, if the destinationViewController property of the segue is NOT an instance of MasterViewController, then either the segue is not correctly configured or your code is in the wrong place.
If I'm mistaken please post more code.

Related

UITableView is not Getting displayed in iPhone

I am using Xcode 3.2.3.
Now i am doing simple UITable view.For that i referred this link.
I have done all the steps mentioned there.
But when my application starts it shows only white screen. No any tableview.
please provide me solution.
Thanks in advance.
MyCode is
AppDelegate.h
#import <UIKit/UIKit.h>
#class TableBasicsViewController;
#interface TableBasicsAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
TableBasicsViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet TableBasicsViewController *viewController;
#end
AppDelegate.m
#import "AppDelegate.h"
#import "TableBasicsViewController.h"
#implementation TableBasicsAppDelegate
#synthesize window;
#synthesize viewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
}
- (void)applicationWillTerminate:(UIApplication *)application {
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
#end
TableBasicViewController.h
#import <UIKit/UIKit.h>
#interface TableBasicsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
}
#property (nonatomic, retain) NSArray *games;
#end
TableBasicViewController.m
#import "TableBasicsViewController.h"
#implementation TableBasicsViewController
#synthesize games;
/*
// Implement loadView to create a view hierarchy programmatically, without using a nib.
- (void)loadView {
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
self.games = [NSArray arrayWithObjects: #"Super Mario Bros.",
#"The Legend of Zelda", #"Blades of Steel",
#"Teenage Mutant Ninja Turtles", #"Excitebike",
#"Dr. Mario", #"Duck Hunt", #"Tetris", #"Ice Climber",
#"River City Ransom", #"Ninja Gaiden", #"Super Mario Bros. 3",
#"Mega Man 2", #"Kid Icarus", #"Metroid", #"Metal Gear",
#"Super Mario Bros. 2", #"Zelda II: The Adventure of Link",
nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section {
return [self.games count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Default";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
// Configure the cell.
cell.textLabel.text = [self.games objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"Selected: '%#'", [self.games objectAtIndex:indexPath.row]);
}
/*
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
*/
- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
self.games = nil;
[super dealloc];
}
#end
Please check this
TableBasicViewController.h
#interface TableBasicsViewController : UIViewController <UITableViewDataSource, UITableViewDelegate> {
IBOutlet UITableView *tableView;
}
#property (nonatomic, retain) NSArray *games;
#end
and link this in your xib too
Write This Code in Your AppDelegate.m File
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
viewController = [[TableBasicsViewController alloc]initWithNibName:#"TableBasicsViewController"];
[window addSubview:viewController.view];
[window makeKeyAndVisible];
return YES;
}

Master Detail Application - Static Table in Detail View

I'm trying to code an app in Xcode 4, with storyboarding. It's a master detail application, and it all worked fine, with the table and the detail view. But in my detail view, I would like to have a static table to display the data. In a grouped table style way, with the "key" on the left and "value" on the right, if that's a way to put it... So, it's all working fine until I put a table into my UIView. Apparently you have to put it in a UITableView for it to work, so I deleted the UIView that Xcode made for me and put in a UITableView in its place. I set it up EXACTLY the same (I think) with the identifier, title etc... and then connect the table cells up with outlets and what not. But now when I enter the view, I just get an empty table (well, not empty, just all the rows say "Detail" in rather than the actual data I want). I don't see why! D: I even changed DetailViewController.h to say "UITableViewController" as well! No avail... :( Could someone please enlighten me as to what I'm doing wrong! I bet it's really simple... :L Here's my code
MasterViewController.h
#import <UIKit/UIKit.h>
#class DetailViewController;
#interface MasterViewController : UITableViewController
#property (strong, nonatomic) DetailViewController *detailViewController;
#property (strong) NSMutableArray *verbs;
#end
MasterViewController.m
#import "MasterViewController.h"
#import "DetailViewController.h"
#import "VerbData.h"
#interface MasterViewController () {
NSMutableArray *_objects;
}
#end
#implementation MasterViewController
#synthesize verbs = _verbs;
- (void)awakeFromNib
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
self.clearsSelectionOnViewWillAppear = NO;
self.contentSizeForViewInPopover = CGSizeMake(320.0, 600.0);
}
[super awakeFromNib];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.detailViewController = (DetailViewController *) [[self.splitViewController.viewControllers lastObject] topViewController];
self.title = #"Verbs";
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
- (void)insertNewObject:(id)sender
{
if (!_objects) {
_objects = [[NSMutableArray alloc] init];
}
[_objects insertObject:[NSDate date] atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _verbs.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"VerbCell"];
VerbData *verb = [self.verbs objectAtIndex:indexPath.row];
cell.textLabel.text = verb.infinitive;
cell.detailTextLabel.text = verb.english;
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_objects removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
}
}
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
VerbData *object = [self.verbs objectAtIndex:indexPath.row];
self.detailViewController.detailItem = object;
}
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
VerbData *object = [self.verbs objectAtIndex:indexPath.row];
[[segue destinationViewController] setDetailItem:object];
}
}
#end
DetailViewController.h
#import <UIKit/UIKit.h>
#import "VerbData.h"
#interface DetailViewController : UITableViewController <UISplitViewControllerDelegate>
#property (strong, nonatomic) VerbData *detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#property (weak, nonatomic) IBOutlet UILabel *jeOutlet;
#property (weak, nonatomic) IBOutlet UILabel *tuOutlet;
#property (weak, nonatomic) IBOutlet UILabel *ilOutlet;
#property (weak, nonatomic) IBOutlet UILabel *nousOutlet;
#property (weak, nonatomic) IBOutlet UILabel *vousOutlet;
#property (weak, nonatomic) IBOutlet UILabel *ilsOutlet;
#end
DetailViewController.m
#import "DetailViewController.h"
#interface DetailViewController ()
#property (strong, nonatomic) UIPopoverController *masterPopoverController;
- (void)configureView;
#end
#implementation DetailViewController
#pragma mark - Managing the detail item
#synthesize detailItem = _detailItem;
#synthesize jeOutlet = _jeOutlet;
#synthesize tuOutlet = _tuOutlet;
#synthesize ilOutlet = _ilOutlet;
#synthesize nousOutlet = _nousOutlet;
#synthesize vousOutlet = _vousOutlet;
#synthesize ilsOutlet = _ilsOutlet;
- (void)setDetailItem:(id)newDetailItem
{
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
if (self.masterPopoverController != nil) {
[self.masterPopoverController dismissPopoverAnimated:YES];
}
}
- (void)configureView
{
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = self.detailItem.english;
self.jeOutlet.text = self.detailItem.je;
self.tuOutlet.text = self.detailItem.tu;
self.ilOutlet.text = self.detailItem.il;
self.nousOutlet.text = self.detailItem.nous;
self.vousOutlet.text = self.detailItem.vous;
self.ilsOutlet.text = self.detailItem.ils;
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.title = self.detailItem.infinitive;
[self configureView];
}
- (void)viewDidUnload
{
[self setJeOutlet:nil];
[self setTuOutlet:nil];
[self setIlOutlet:nil];
[self setNousOutlet:nil];
[self setVousOutlet:nil];
[self setIlsOutlet:nil];
[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 - Split view
- (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController
{
barButtonItem.title = NSLocalizedString(#"Master", #"Master");
[self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES];
self.masterPopoverController = popoverController;
}
- (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem
{
// Called when the view is shown again in the split view, invalidating the button and popover controller.
[self.navigationItem setLeftBarButtonItem:nil animated:YES];
self.masterPopoverController = nil;
}
#end
First thing I will try to debug is -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method. Is it return values? Try to put NSLog in this method and check it.
Or maybe this will help you:
Note: If you want to change the background color of a cell (by setting the background color of a cell via the backgroundColor property declared by UIView) you must do it in the tableView:willDisplayCell:forRowAtIndexPath: method of the delegate and not in tableView:cellForRowAtIndexPath: of the data source. Changes to the background colors of cells in a group-style table view has an effect in iOS 3.0 that is different than previous versions of the operating system. It now affects the area inside the rounded rectangle instead of the area outside of it.
The code must handle the case where dequeueReusableCellWithIdentifier answers nil...
static NSString *CellIdentifier = #"VerbCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}

StoryBoard iOS 5 - Custom UITableViewCell Crash Scrolling up

I have been coding a example of a UITableView with a custom UITableViewCell (PlayerCell). All work fine, I can see the elements in my table and I can select them, but when I do a scroll up, the app crash. I have reviewed the identifier, the class of the controller, everything, but when I use a custom cell, it not works. If I use a default style, it works fine, inclusive the scroll up.
I think I have the problem in this method: didSelectRowAtIndexPath
But the debugger, don't show me an error, only something like: EXEC BAD ADRESSS (I don't have the computer here)
This is my code:
MyTeamViewController.h
#import <UIKit/UIKit.h>
#interface MyTeamViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *players;
#end
MyTeamViewController.m
#import "MyTeamViewController.h"
#import "Player.h"
#import "PlayerCell.h"
#interface MyTeamViewController ()
#end
#implementation MyTeamViewController
#synthesize players;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
// Override point for customization after application launch.
players = [NSMutableArray arrayWithCapacity:20];
Player *player = [[Player alloc] init];
player.name = #"Bill Evans";
player.game = #"Tic-Tac-Toe";
player.rating = 4;
[players addObject:player];
player = [[Player alloc] init];
player.name = #"Oscar Peterson";
player.game = #"Spin the Bottle";
player.rating = 5;
[players addObject:player];
player = [[Player alloc] init];
player.name = #"Dave Brubeck";
player.game = #"Texas Hold’em Poker";
player.rating = 2;
[players addObject:player];
[super viewDidLoad];
// 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)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
//#warning Potentially incomplete method implementation.
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
// Return the number of rows in the section.
NSUInteger numberCells = players.count;
return numberCells;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"PlayerCell";
PlayerCell *cell = (PlayerCell *)[tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil)
{
NSLog(#"Cell is NIL");
//I don't know what put here <-- MY PROBLEM!!! :(
}
Player *player = [self.players objectAtIndex:indexPath.row];
cell.nameLabel.text = player.name;
cell.pointsLabel.text = player.game;
cell.clubImageView.image = [self
imageForRating:player.rating];
// Configure the cell...
return cell;
}
- (UIImage *)imageForRating:(int)rating
{
switch (rating)
{
case 1: return [UIImage imageNamed:#"1StarSmall.png"];
case 2: return [UIImage imageNamed:#"2StarsSmall.png"];
case 3: return [UIImage imageNamed:#"3StarsSmall.png"];
case 4: return [UIImage imageNamed:#"4StarsSmall.png"];
case 5: return [UIImage imageNamed:#"5StarsSmall.png"];
}
return nil;
}
/*
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the specified item to be editable.
return YES;
}
*/
/*
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
{
}
*/
/*
// Override to support conditional rearranging of the table view.
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
// Return NO if you do not want the item to be re-orderable.
return YES;
}
*/
#pragma mark - Table view delegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
/*
<#DetailViewController#> *detailViewController = [[<#DetailViewController#> alloc] initWithNibName:#"<#Nib name#>" bundle:nil];
// ...
// Pass the selected object to the new view controller.
[self.navigationController pushViewController:detailViewController animated:YES];
[detailViewController release];
*/
}
#end
The other files:
Player.h
#import <Foundation/Foundation.h>
#interface Player : NSObject
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *game;
#property (nonatomic, assign) int rating;
#end
Player.m
#import "Player.h"
#implementation Player
#synthesize name;
#synthesize game;
#synthesize rating;
#end
PlayerCell.h
#import <UIKit/UIKit.h>
#interface PlayerCell : UITableViewCell
#property (nonatomic, strong) IBOutlet UILabel *nameLabel;
#property (nonatomic, strong) IBOutlet UILabel *pointsLabel;
#property (nonatomic, strong) IBOutlet UIImageView
*clubImageView;
#end
PlayerCell.m
#import "PlayerCell.h"
#implementation PlayerCell
#synthesize nameLabel;
#synthesize pointsLabel;
#synthesize clubImageView;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
#end
Thank you so much!!
EDIT: I solved it with: players = [[NSMutableArray arrayWithCapacity:20] retain];
I would try to remove the
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
In the PlayerCell.m - u don't need them.

EXC_BAD_ACCESS error happens in an UITableViewController with subclassed UITableViewCell

I have an UITableViewController to manage an table view which created with subclassed prototype cells. The most related codes is as following:
MyCell.h
#import <UIKit/UIKit.h>
#interface ScrollViewTableCellInShorTrip : UITableViewCell
#end
MyCell.m
#import "MyCell.h"
#implementation SMyCell
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event
{
NSLog(#"touch cell");
[super touchesEnded: touches withEvent: event];
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
}
}
#end
TableViewController.h
#import <UIKit/UIKit.h>
#interface TableViewController : UITableViewController{
}
#property (nonatomic, retain) NSArray *arr;
#end
TableViewController.m
#import "TableViewController.h"
#import "MyCell.h"
#implementation ATripTableViewController
#synthesize arr;
- (void)viewDidLoad
{
[super viewDidLoad];
self.arr = [NSArray arrayWithObjects:#"one", #"two", #"three", nil];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
CellIdentifier = #"myCell";
MyCell *myCell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
return myCell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self performSegueWithIdentifier:#"detailView"sender:self];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"detailView"]){
NSLog(#"arr acount is %d", self.arr.count);//program received signal: "EXC_BAD_ACCESS".
}
}
EXC_BAD_ACCESS error message is appear when calls "NSLog(#"arr acount is %d", self.arr.count)" in the prepareForSegue:sender: method. It is obviously that the property "arr" is free now. And The situation appears only when i use the subclassed UITableViewCell.
Appreciate any answers!
NSLog(#"arr acount is %d", self.arr.count); replace to NSLog(#"arr acount is %d",arr.count);
definition of self:
self is a special variable which is a pointer to the object which received the message which invoked the currently executing method(!). In other words, it is the receiver of the message.
when you should call self.object rather than calling the object directly within an object.
self.object = obj;
object = obj;
The difference between these two calls is that a call to self.object will make use of the accessors generated by the #synthesize directive. A call to the object directly will bypass these accessor methods and directly modify the instance variable
count is a primitive (integer), not an object, as you are referring to it as with %#. use %i instead.

Custom UITableViewCells

I am actually very surprised how difficult it is to keep your code well structured and readable when doing iphone app stuff... but it might be because I am doing something wrong.
I have a Sign Up page containing different kinds of inline-editable data: birthday, gender, name, password, phone number. I have made the page as a table view of custom cells where each cell is an instance of a sub class of UITableViewCell and is read from its own nib file. This because I thought that I then might be able to reuse these different kinds of cells later in other table view pages.
The approach of encapsulating the different custom cells in their own place is not working that well though:
Who is going to be the controller of e.g the gender picker inside the GenderCell?
How am I actually going to reuse the cells in a different table view controller when I had to put the SignUpController as the file's owner of the cell nib files?
I do not know if anyone but myself understood what I just wrote, but if so, I would be very thankful for any suggestions on how to structure my code differently.
Thanks a lot,
Stine
To make things more clear (?!) let me paste some of my code in here:
EditableLabel.h
#interface EditableLabel : UILabel {
UIView *inputView, *inputAccessoryView;
}
#property (nonatomic, retain) UIView *inputView, *inputAccessoryView;
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar;
#end
EditableLabel.m
#implementation EditableLabel
#synthesize inputView, inputAccessoryView;
- (void) dealloc {
[inputView release];
[inputAccessoryView release];
[super dealloc];
}
- (void) setInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
self.inputAccessoryView = aToolbar;
self.inputView = aView;
}
- (BOOL) canBecomeFirstResponder {
return YES;
}
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self becomeFirstResponder];
}
#end
EditableCell.h
typedef enum {
USERNAME, PASSWORD, MOBILE, BIRTHDAY, GENDER, DESCRIPTION, CATEGORY
} CellTag;
#interface EditableCell : UITableViewCell {
CellTag tag;
UIView *editPoint;
IBOutlet UILabel *headerLabel;
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView;
#property (nonatomic) CellTag tag;
#property (nonatomic, retain) UIView *editPoint;
#property (nonatomic, retain) UILabel *headerLabel;
- (IBAction) editingDone:(id)sender;
- (void) showInputView;
- (void) hideInputView;
#end
EditableCell.m
#implementation EditableCell
#synthesize tag, editPoint, headerLabel;
- (void) dealloc {
[editPoint release];
[headerLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andEditPoint:(UIView *)aView {
self.tag = aTag;
self.headerLabel.text = aHeader;
self.editPoint = aView;
}
- (IBAction) editingDone:(id)sender {
[self hideInputView];
}
- (void) showInputView {
[self.editPoint becomeFirstResponder];
}
- (void) hideInputView {
[self.editPoint resignFirstResponder];
}
#end
EditableLabelCell.h
#interface EditableLabelCell : EditableCell {
IBOutlet UILabel *placeHolderLabel;
IBOutlet EditableLabel *editableLabel;
}
#property (nonatomic, retain) UILabel *placeHolderLabel;
#property (nonatomic, retain) EditableLabel *editableLabel;
- (void) setTag:(CellTag)aTag
andHeader:(NSString *)aHeader
andPlaceHolder:(NSString *)aPlaceHolder
andInputView:(UIView *)aView
andToolbar:(UIToolbar *)aToolbar;
- (void) setValue:(NSString *)aValue;
#end
EditableLabelCell.m
#implementation EditableLabelCell
#synthesize placeHolderLabel, editableLabel;
- (void) dealloc {
[placeHolderLabel release];
[editableLabel release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andHeader:(NSString *)aHeader andPlaceHolder:(NSString *)aPlaceHolder andInputView:(UIView *)aView andToolbar:(UIToolbar *)aToolbar {
[super setTag:aTag andHeader:aHeader andEditPoint:self.editableLabel];
self.placeHolderLabel.text = aPlaceHolder;
[self.editableLabel setInputView:aView andToolbar:aToolbar];
}
- (void) setValue:(NSString *)aValue {
if (aValue && aValue != #"") {
self.placeHolderLabel.hidden = YES;
self.editableLabel.text = aValue;
} else {
self.editableLabel.text = nil;
self.placeHolderLabel.hidden = NO;
}
}
#end
EditableGenderCell.h
#protocol EditableGenderCellDelegate <NSObject>
#required
- (NSString *) getTextForGender:(Gender)aGender;
- (void) genderChangedTo:(Gender)aGender forTag:(CellTag)aTag;
#end
#interface EditableGenderCell : EditableLabelCell <UITableViewDataSource, UITableViewDelegate> {
id<EditableGenderCellDelegate> delegate;
Gender gender;
IBOutlet UITableView *genderTable;
IBOutlet UIToolbar *doneBar;
}
- (void) setTag:(CellTag)aTag
andDelegate:(id<EditableGenderCellDelegate>)aDelegate
andHeader:(NSString *)aHeader
andGender:(Gender)aGender
andPlaceHolder:(NSString *)aPlaceHolder;
#property (nonatomic, retain) id<EditableGenderCellDelegate> delegate;
#property (nonatomic) Gender gender;
#property (nonatomic, retain) UITableView *genderTable;
#property (nonatomic, retain) UIToolbar *doneBar;
#end
EditableGenderCell.m
#implementation EditableGenderCell
#synthesize delegate, gender, genderTable, doneBar;
- (void) dealloc {
[delegate release];
[genderTable release];
[doneBar release];
[super dealloc];
}
- (void) setTag:(CellTag)aTag andDelegate:(id<EditableGenderCellDelegate>)aDelegate andHeader:(NSString *)aHeader andGender:(Gender)aGender andPlaceHolder:(NSString *)aPlaceHolder {
[super setTag:aTag andHeader:aHeader andPlaceHolder:aPlaceHolder andInputView:self.genderTable andToolbar:self.doneBar];
self.delegate = aDelegate;
self.gender = aGender;
[super setValue:[self.delegate getTextForGender:aGender]];
}
#pragma mark - Table view data source
- (NSInteger) numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 2;
}
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
switch (indexPath.row) {
case MALE:
switch (self.gender) {
case MALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
case FEMALE:
switch (self.gender) {
case FEMALE:
cell.accessoryType = UITableViewCellAccessoryCheckmark;
break;
default:
cell.accessoryType = UITableViewCellAccessoryNone;
}
break;
}
cell.textLabel.text = [self.delegate getTextForGender:indexPath.row];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
#pragma mark - Table view delegate
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.gender = indexPath.row;
[super setValue:[self.delegate getTextForGender:self.gender]];
[self.delegate genderChangedTo:self.gender forTag:self.tag];
[tableView reloadData];
}
#end
Have a look at my answer to How to make a UITableViewCell with different subviews reusable?.
You should back up your custom tableviewcell nib files with a custom class representing your cell and encapsulate logic in it for example your gender picker. If you need to inform some outside controller of the gender you can make use of the delegate pattern.
Custom Gender picker in a TableViewCell
Ok let's start with the nib file, looking like this:
view hierarchy, don't set the File's Owner...
...set instead the class of the table view cell of your custom class:
The custom class
As you can see the class is almost empty, only providing the segmented control as property
GenderPickerTableViewCell.h
#interface GenderPickerTableViewCell : UITableViewCell
{
UISegmentedControl *genderPickerSegmentedControl;
}
#property (nonatomic, retain) IBOutlet UISegmentedControl *genderPickerSegmentedControl;
#end
GenderPickerTableViewCell.m
#import "GenderPickerTableViewCell.h"
#implementation GenderPickerTableViewCell
#synthesize genderPickerSegmentedControl;
#pragma mark -
#pragma mark memory management
- (void)dealloc
{
[genderPickerSegmentedControl release];
[super dealloc];
}
#pragma mark -
#pragma mark initialization
- (void)awakeFromNib
{
// initialization goes here, for example preselect a specific gender
}
#end
The table view using our new cell
I'll provide only the necessary methods to make this work. The TableViewCellFactory class is just a nib loader like I posted in my referenced answer above. The genderPickerTableViewCellWithTableView is just a convenience class method to return that special kind of cell without too much boilerplate code
The last important thing to note is the configuration of the cell, this is kept simple, I just access the segmented control directly and add a target to it which informs this view controller about a change.
#pragma mark -
#pragma mark view lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
tableView.rowHeight = 100.0;
tableView.dataSource = self;
tableView.delegate = self;
}
#pragma mark -
#pragma mark UITableView methods
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
- (UITableViewCell *) tableView:(UITableView *)aTableView cellForRowAtIndexPath:(NSIndexPath *)anIndexPath
{
GenderPickerTableViewCell *cell = [TableViewCellFactory genderPickerTableViewCellWithTableView:aTableView];
[cell.genderPickerSegmentedControl addTarget:self
action:#selector(genderPicked:)
forControlEvents:UIControlEventValueChanged];
return cell;
}
#pragma mark -
#pragma mark UISegmentedControl action
- (void)genderPicked:(id)sender
{
UISegmentedControl *segmentedControl = (UISegmentedControl *)sender;
NSLog(#"selected index: %d", [segmentedControl selectedSegmentIndex]);
}
I hope this helps a bit for the beginning.
This is the code you can use for bouncing:
-(IBAction)textFieldDidBeginEditing:(UITextField *)textField { //Keyboard becomes visible
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3];
self.view.frame = CGRectMake(self.view.frame.origin.x, self.view.frame.origin.y - 50, self.view.frame.size.width, self.view.frame.size.height);
[UIView commitAnimations];
}
Just set y accordingly an call it when editing begins.