I have a UITableView in a UIViewController. I have other UIViewControllers created in Storyboard that I want to connect to my cells.
How can I connect UIViewControllers created in Storyboard to my cells?
MyViewController.h
#interface MyViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
IBOutlet UITableView *myTableView;
}
#property (nonatomic, retain) UITableView *myTableView;
MyViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *array = [[NSArray alloc] initWithObjects:#"CELL1", #"CELL2 & CELL3", nil];
self.listData = array;
[array release];
[myTableView setDataSource:self];
[myTableView setDelegate:self];
[[self view] addSubview:myTableView];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [listData count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UpdatesTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"UpdatesTableViewCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (UpdatesTableViewCell*)view;
}
}
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [listData objectAtIndex:row];
return cell;
}
You can either create segues from this controller to the other ones and then choose which segue to perform when someone taps a cell or you can use a reference to the storyboard to call instantiateViewControllerWithIdentifier: and make that controller active on a tap.
Related
I want to populate a UITableView by passing a string from a UIViewController to a UITableView.
This is my code so far:
UITableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSMArray = [[NSMutableArray alloc]initWithObjects:#"text",#"text2", nil];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return NSMArray.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier ];
}
cell.textLabel.text = [NSMArray objectAtIndex:indexPath.row];
return cell;
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
return YES;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
//remove fron NSMutableArray
[NSMArray removeObjectAtIndex:indexPath.row];
//delete from table
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
}
-(void)getString:(NSString *)string
{
if ([make length] > 0) {
if (!NSMArray)
{
NSMArray = [[NSMutableArray alloc]init];
}
[NSMArray insertObject:make atIndex:0];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[self.myTableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
UITableViewController.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (strong, nonatomic) IBOutlet UITableView *myTableView;
#property (strong, nonatomic) NSMutableArray *NSMArray;
-(void)getString:(NSString *)string;
ViewController.m
#import "entryViewController.h"
#interface entryViewController ()
#end
#implementation entryViewController
#synthesize textfieldString, myString;
- (void)viewDidLoad
{
[super viewDidLoad];
//Save button
UIBarButtonItem *SaveButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:#selector(pushCarMake:)];
self.navigationItem.rightBarButtonItem = SaveButton;
}
- (void)pushCarMake:(id)sender
{
myString = textfieldString.text;
ViewController *mainVC = [[ViewController alloc]init];
[mainVC getString:myString];
//pop to root ViewController
[self.navigationController popToRootViewControllerAnimated:TRUE];
}
#end
ViewCotroller.h
#import <UIKit/UIKit.h>
#import "ViewController.h"
#interface entryViewController : UIViewController
#property (strong, nonatomic) NSString *carMake;
#property (strong, nonatomic) IBOutlet UITextField *textfieldCarMake;
So this works fine and populates the Table View with the string items instantiated in the viewDidLoad of the UITableViewCotroller. But every time I pass a string from the ViewControllers to the table View it does not go into the table. any suggestions why this is. Sorry for pasting so much code.
One approach for passing data from a detail view controller back to it's parent is using a delegate. Here's an example:
How do I set up a simple delegate to communicate between two view controllers?
[Edited]
The other approach if you're using storyboards is to use an unwind segue. Here's a sample I put together using this approach: github.com/soleares/AddToTableView
Not positive if this is the only issue, but try adding beginUpdates and endUpdate
[myTableView beginUpdates];
[self.myTableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
[myTableView endUpdates];
I have this UIWebView inside a custom UITableViewCell that I've created.
The problem is, when I implement the UIWebView in "MyMain", it's working but when I scroll the text is readded again and again on over the cells.
When I implement the UIWebView in the custom cell class itself it's not showing it at all.
UITableViewCustomCell.h
#property (nonatomic, weak) IBOutlet UIWebView *wvMainText;
#property (nonatomic, strong) NSString *wvTitle;
#property (nonatomic, strong) NSString *wvPrice;
UITableViewCustomCell.m
#synthesize wvMainText = _wvMainText;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self)
{
// THIS IS WHERE I IMPLEMENT THE WEBVIEW?
}
return self;
}
MyMain
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myListCell";
UITableViewCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"UITableViewCustomCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (UITableViewCustomCell *)view;
}
}
}
cell.wvTitle = [[self.arrList objectAtIndex:indexPath.row] valueForKey:#"title"];
cell.wvPrice = [[self.arrList objectAtIndex:indexPath.row] valueForKey:#"price"];
wv.scrollView.scrollEnabled = NO;
NSString *htmlString = [NSString stringWithFormat:
#"<html><body>%#,%#</body></html>", self.wvTitle, self.wvPrice];
[wv loadHTMLString:htmlString baseURL:nil];
[wv setBackgroundColor:[UIColor clearColor]];
[wv setOpaque:NO];
return cell;
}
Try this...It may solve your issue.
In your cellForRowAtIndexPath method please do changes like this....
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"myListCell";
UITableViewCustomCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray* views = [[NSBundle mainBundle] loadNibNamed:#"UITableViewCustomCell" owner:nil options:nil];
for (UIView *view in views) {
if([view isKindOfClass:[UITableViewCell class]])
{
cell = (UITableViewCustomCell *)view;
}
}
cell.wvTitle = [[self.arrList objectAtIndex:indexPath.row] valueForKey:#"title"];
cell.wvPrice = [[self.arrList objectAtIndex:indexPath.row] valueForKey:#"price"];
wv.scrollView.scrollEnabled = NO;
NSString *htmlString = [NSString stringWithFormat:
#"<html><body>%#,%#</body></html>", self.wvTitle, self.wvPrice];
[wv loadHTMLString:htmlString baseURL:nil];
[wv setBackgroundColor:[UIColor clearColor]];
[wv setOpaque:NO];
}
return cell;
}
I have created a iPad app that has a settings form sheet. The form sheet is using two subviews for create a split view like display. The left (master) UITableView scrolls and launches fine. The error is coming in from when one of the master cells is selected and it displays a UITableView from a UITableViewController into the right(detail) view. It will display the UITableView but once it is scrolled the detail view crashes. Yes I have the list pulling from plist because I want these results be be accessed later in other places of the application.
this is the View Controller for the form sheet and delegate for Master View
.h file
#interface settingsViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>{
UITableView *mainTableView;
NSDictionary *mainSettingList;
NSArray *settingItems;
}
#property (weak, nonatomic) IBOutlet UINavigationBar *settingsNavigationBar;
#property (weak, nonatomic) IBOutlet UITableView *mainTableView;
#property (weak, nonatomic) IBOutlet UIView *borderView;
#property (strong, nonatomic) IBOutlet UIView *detailView;
.m file
#property (nonatomic, strong)NSDictionary *mainSettingList;
#property (nonatomic, strong)NSArray *settingItems;
#end
#implementation settingsViewController
#synthesize settingsNavigationBar = _settingsNavigationBar;
#synthesize mainTableView = _mainTableView;
#synthesize borderView = _borderView;
#synthesize settingItems, mainSettingList;
-(void)viewDidLoad{
[super viewDidLoad];
[self.detailView setFrame:CGRectMake(233, 0, 310, 620)];
[self.borderView setBackgroundColor:[UIColor lightGrayColor]];
[self.view addSubview:self.borderView];
[self.view addSubview:self.detailView];
}
- (IBAction)closePressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
-(NSDictionary *)mainSettingList{
if(!mainSettingList){
NSString *str_settingList = [[NSBundle mainBundle]pathForResource:#"settingsList" ofType:#"plist"];
mainSettingList = [NSDictionary dictionaryWithContentsOfFile:str_settingList];
self.mainSettingList = mainSettingList;
}
return mainSettingList;
}
-(NSArray *)settingItems{
if(!settingItems){
settingItems = [[self.mainSettingList allKeys]sortedArrayUsingSelector:#selector(compare:)];
self.settingItems = settingItems;
}
return settingItems;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.settingItems.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *wordsInSection = [self.mainSettingList objectForKey:
[self.settingItems objectAtIndex:section]];
return wordsInSection.count;
}
-(NSString *)nameAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *wordsInSection = [self.mainSettingList objectForKey:[self.settingItems objectAtIndex:indexPath.section]];
return [wordsInSection objectAtIndex:indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"AlumniListCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [self nameAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.settingItems objectAtIndex:section];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UINavigationController *nvc = [[UINavigationController alloc]init];
[nvc.view setFrame:CGRectMake(0,0, 310, 620)];
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = selectedCell.textLabel.text;
if([cellText isEqualToString:#"Types of Jumps"]){
TypesOfJumps *toj = [[TypesOfJumps alloc]initWithNibName:#"TypesOfJumps" bundle:nil];
[nvc pushViewController:toj animated:YES];
}
[self.detailView addSubview:nvc.view];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithFormat:#"You selected %#!", cellText] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation{
return YES;
}
- (void)viewDidUnload {
[self setSettingsNavigationBar:nil];
[self setBorderView:nil];
[self setMainTableView:nil];
[self setSubViewNavigaionBar:nil];
[self setDetailView:nil];
[super viewDidUnload];
}
#end
UITableViewController called by cell pressed method
.h file
#interface TypesOfJumps : UITableViewController<UITableViewDataSource,UITableViewDelegate>{
NSDictionary *listJumps;
NSArray *typesJumps;
}
#property (strong, nonatomic) IBOutlet UITableView *tableView;
.m file
#interface TypesOfJumps ()
#property (strong, nonatomic)NSDictionary *listJumps;
#property (strong, nonatomic)NSArray *typesJumps;
#end
#implementation TypesOfJumps
#synthesize listJumps = _listJumps;
#synthesize typesJumps = _typesJumps;
#synthesize tableView = _tableView;
-(NSDictionary *)listJumps{
if(!listJumps){
NSString *str_settingList = [[NSBundle mainBundle]pathForResource:#"TypesOfJumps" ofType:#"plist"];
listJumps = [NSDictionary dictionaryWithContentsOfFile:str_settingList];
self.listJumps = listJumps;
}
return listJumps;
}
-(NSArray *)typesJumps{
if(!typesJumps){
typesJumps = [[self.listJumps allKeys]sortedArrayUsingSelector:#selector(compare:)];
self.typesJumps = typesJumps;
}
return typesJumps;
}
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return self.typesJumps.count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSArray *wordsInSection = [self.listJumps objectForKey:
[self.typesJumps objectAtIndex:section]];
return wordsInSection.count;
}
-(NSString *)nameAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *wordsInSection = [self.listJumps objectForKey:[self.typesJumps objectAtIndex:indexPath.section]];
return [wordsInSection objectAtIndex:indexPath.row];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"AlumniListCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell...
cell.textLabel.text = [self nameAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
-(NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return [self.typesJumps objectAtIndex:section];
}
I have a table view, and if a certain row is tapped, the detail view will show up. But how does the detail view know which row was tapped ?
So for instance, I have a MainController which displays names. If I tap "Johnny" The next screen should show a label with the string "Johnny". How would I do that ?
[EDIT - Added code]
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
ArticleView *article = [self.storyboard instantiateViewControllerWithIdentifier:#"ArticleView"];
[article.myLabel setText:#"random"];
[self.navigationController pushViewController:article animated:YES];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
}
NSDictionary *info = [json objectAtIndex:indexPath.row];
cell.textLabel.text = [info objectForKey:#"username"];
cell.textLabel.backgroundColor = nil;
cell.textLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.backgroundColor = nil;
cell.detailTextLabel.textColor = [UIColor whiteColor];
cell.detailTextLabel.text = [info objectForKey:#"user_pic"];
// Configure the cell...
return cell;
}
ArticleView.h
#interface ArticleView : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *myLabel;
#end
ArticleView.m
-> Synthesizing properties
You could pass a object (i.e. the String Jonny) to the detail view controller as a property.
#interface ArticleViewController : UIViewController
#property (retain) ArticleView *articleView;
#end
//Don't forget to synthesize name
in the tableview controller
-(void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath)indexPath
{
NSDictionary *info = [json objectAtIndex:indexPath.row];
ArticleViewController *articleViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ArticleViewController"];
articleViewController.articleView = articleView;
[self.navigationController pushViewController: articleViewController animated:YES];
}
the table view delegate has the method tableView:didSelectRowAtIndexPath:, in this method you present your detail view so you know which row was selected from the indexPath parameter and can pass any info you need when you create the new view controller
Assuming you're talking iPhone here, I would have a property name on my detail view:
#propery (nonatomic, retain) NSString * name;
and an init method as follows:
- (id) initWithName: (NSString *) name
{
self = [super initWithNibName: #"<view-controller-nib-name>" bundle: nil];
if (self) {
self.name = name;
}
return self;
}
and then set name label in viewDidLoad
In the tableView:didSelectRowAtIndexPath: method, get the name referenced by the index path, create and init a detail view controller using initWithName:, then push on the nav stack.
I create tableView with my custom cells.
here the code of the cell .h file
#interface ZUITableViewCell : UITableViewCell {
IBOutlet UITextField *_textFieldOutlet;
IBOutlet UILabel *_textLabelOutlet;
}
#property (retain, nonatomic) IBOutlet UITextField *_textFieldOutlet;
#property (retain, nonatomic) IBOutlet UILabel *_textLabelOutlet;
#end
And in my tableview controller file I create this
#import <UIKit/UIKit.h>
#import "ZUITableViewCell.h"
#protocol ZUITableViewControllerDelegate ///for main view controller
-(void) doneButtonPressed;
#end
#interface ZUITableViewController : UITableViewController {
id <ZUITableViewControllerDelegate> delegate;
NSMutableArray *menuItems;
BOOL isAddingFields;
}
#property (nonatomic, retain) NSArray *menuItems;
#property (nonatomic, assign) id<ZUITableViewControllerDelegate> delegate;
- (CGRect) GetCellHegiht: (ZUITableViewCell *) cell;
#end
I want to add new rows in my table view when user select the second row.
To make this I describe this method
- (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];
*/
NSLog (#"row = %d", indexPath.row);
NSLog(#"INIT %p", self);
ZUITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
[cell._textFieldOutlet becomeFirstResponder];
if (indexPath.row == 1 && isAddingFields == FALSE) {
isAddingFields = TRUE;
[menuItems insertObject:#"CC" atIndex:1];
[menuItems insertObject:#"BCC" atIndex:2];
NSIndexPath *path1 = [NSIndexPath indexPathForRow:1 inSection:0];
NSIndexPath *path2 = [NSIndexPath indexPathForRow:2 inSection:0];
NSArray *indexArray = [NSArray arrayWithObjects:path1,path2,nil];
[tableView insertRowsAtIndexPaths:indexArray withRowAnimation:UITableViewRowAnimationTop];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[path1 release];
[path2 release];
[cell._textFieldOutlet becomeFirstResponder];
}
}
and there is my cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
NSLog(#"INIT %p", self);
NSLog (#"cell for row = %d", indexPath.row);
ZUITableViewCell *cell = (ZUITableViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelsObjects = [[NSBundle mainBundle] loadNibNamed:#"ZUITableViewCell" owner:nil options:nil];
for (id currentObject in topLevelsObjects){
if ([currentObject isKindOfClass:[UITableViewCell class]]){
cell = (ZUITableViewCell *) currentObject;
break;
}
}
}
if (indexPath.row == 3 && isAddingFields == FALSE){
// [cell setBounds:[self GetCellHegiht:cell]];
}
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell._textLabelOutlet.text = [menuItems objectAtIndex:indexPath.row];
cell._textFieldOutlet.tag = indexPath.row;
[cell._textFieldOutlet setEnabled:YES];
if(indexPath.row == 0){
[cell._textFieldOutlet becomeFirstResponder];
}
return cell;
}
In debug mode as I can see after clicking to the row with indexPath.row == 1 this controller call method cellForRowAtIndexPath two times with indexPath.row = 1 and 2. But After It controller call method
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
//#warning Incomplete method implementation.
return [menuItems count];
}
again and method cellForRowAtIndexPath calling too, After program take me this error (I enable zombie) Error -[NSIndexPath release]: message sent to deallocated instance 0x6a9d790
The method [NSIndexPath indexPathForRow:inSection:] (used in path1 and path2) returns an autoreleased object, no need to call release after.