How to load array into a UITableView, not TableViewController - objective-c

I am trying to take an array that I loaded from another viewer and put it into a UITableView, not a TableViewController. I don't know how I would do this. Right now I have this code:
CRHCommentSection.m
#import "CRHCommentSection.h"
#import "CRHViewControllerScript.h"
#interface CRHCommentSection ()
#end
#implementation CRHCommentSection
#synthesize observationTable;
NSArray *myArray;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
myArray = [CRHViewControllerScript theArray];
NSLog(#"%#", myArray);
//NSArray* paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:0 inSection:1]];
//[observationTable insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
NSLog(#" in method 1");
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#" in method 2");
// Return the number of rows in the section.
return [myArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#" in method 3");
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.textLabel.text = [myArray objectAtIndex:indexPath.row];
return cell;
}
CRHCommentSection.h
#import <UIKit/UIKit.h>
#interface CRHCommentSection : UIViewController
#property (weak, nonatomic) IBOutlet UITableView *observationTable;
#end

Since you have posted this same example code more than once, Ill give you the way to do this without using statics. And Yes you do need to set the collection (array) on the view controller not the UITableView as the tableView uses the controller as a datasource.
Lets say you had a UITableView that displayed search results... And you launch this view controller from either some other view or from the application delegate like so..
In your viewController (yours is CRHCommentSection) define a property for the array you are going to populate the table with.
#property (nonatomic,retain, setter=setSearchResults:) NSArray *searchResults; //use your array name here
//BTW please dont call it ARRAY..its confusing.
Also in your commentsController (which would be a better name that what you have) add the setter for
the array
-(void) setSearchResults:(NSArray *)searchResults
{
//in case we loaded this view with results previously release the previous results
if ( _searchResults )
{
[_searchResults release];
}
_searchResults = [searchResults retain];
[_tableView reloadData];
}
When you instantiate the new view controller with the UITableView in it - set the "array",
in your case comments in my case searchResults
_searchResultsViewController = [[SearchResultsViewController alloc] initWithNibName:#"SearchResultsViewController" bundle:nil];
//now set the array on the controller
_searchResultsViewController.searchResults = mySearchResults; //(your array)
Thats a simple way to communicate the array for the table view when you instantiate a view controller.
Also the naming conventions will help you clear things up
If you have a view controller for comments it should be
CommentsViewController
And the array if it contains comments should be called comments - for readability.
Cheers.
As for the rest of the boilerplate setting the datasource and delegate and cellForRow etc,
you got that advice on the last go around so I wont repeat it here.
#bigkm had a good point
#interface SearchResultsViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
Your view controller has to be defined properly as above with the protocols.

You need to set the data source
[self setDataSource:self];
And also add the protocol to your interface.
<UITableViewDataSource>

Related

Loading NSArray UITableViewController

I have a tabbed view controller and I put a table view in it but when I run the program I got this EXC_BAD_ACCESS signal.
The array does not get loaded and produces this error.
Here is my code:
ContactsViewController.h
#import <UIKit/UIKit.h>
#interface ContactsViewController : UITableViewController <UITableViewDataSource,UITableViewDelegate>
#property (nonatomic ,retain) NSArray *items;
#end
ContactsViewController.m
#import "ContactsViewController.h"
#interface ContactsViewController ()
#end
#implementation ContactsViewController
#synthesize items;
- (id)initWithStyle:(UITableViewStyle)style {
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
items = [[NSArray alloc] initWithObjects:#"item1", #"item2", "item3", nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [items count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
return cell;
}
#end
The problem with your code lies (as the debugger tells you) in the following line:
items = [[NSArray alloc] initWithObjects:#"item1", #"item2", "item3", nil];
Take a closer look at "item3". There is no # sign in front of it so it is not an NSString object but a plain old C string. You can only put objects into an NSArray.
Change it to
items = [[NSArray alloc] initWithObjects:#"item1", #"item2", #"item3", nil];
or even simpler
item = #[#"item1", #"item2", #"item3"];
Without the rest of the code it's not possible to say for sure what the problem is, but you should access the variable through the property in the following way.
self.items = ...
Also consider using the shorthand array notation, like this.
self.items = #[#"Item 1", #"Item 2", #"Item 3"];
IMO: The only time you should use variables directly is in an overriden property accessory.
Also note that if you do want to use the variable directly you should change the synthesize command to the following #synthesize items = variableName; This puts a name, variableName on the underlying variable used in the property. You can then access the variable without going through the property.

Populate UITableView from button pressed

I am trying to populate UITableView from NSMutableArray. I have UITextField and a button on a ViewController. When I type any text in the UITextField and click button, I can see the text being added to the array with NSLog. I set breakpoints on the data source method of UITableView but it does not even hit those breakpoints when I click the button.
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
{
NSMutableArray *arrBarcode;
IBOutlet UITextField *txtInsert;
}
#property IBOutlet UITableView *myTableView;
-(IBAction)btnPressed:(id)sender;
#end
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.myTableView.delegate = self;
self.myTableView.dataSource = self;
arrBarcode = [[NSMutableArray alloc]init];
}
-(IBAction)btnPressed:(id)sender{
[arrBarcode addObject:txtInsert.text];
NSLog(#"array count is : %i", [arrBarcode count]);
[self.myTableView reloadData];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[txtInsert resignFirstResponder];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger)numberOfSectionsInTableView: (UITableView *)tableView{
return 1;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if ([arrBarcode count] == 0){
return 0;
}
else{
NSLog(#"Number of Rows : %i", [arrBarcode count]);
return [arrBarcode count];
}
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell Identifier";
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
if (cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSString *barcode = [arrBarcode objectAtIndex:[indexPath row]];
[cell.textLabel setText:barcode];
return cell;
}
#end
When I initialize a NSMutable Array with some data in the viewDidLoad method, the UITableView is populating fine but not with dynamic array. I am newbie in Objective C, Can someone point me to right direction?
Code looks OK (even if not very efficient). You have to check if the button is indeed connected to the action. In storyboard or Interface Builder, select the button and check the rightmost inspector on the right. See if the action is correctly connected.
Maybe you want to get rid of the touchesBegan call and call resignFirstResponder when the button is pressed.
For numberOfRowsInSection I think this is enough:
return arrBarcode.count;
I'm not sure but the following line looks strange to me:
#synthesize myTableView = myTableView_;
This is telling the compiler to make a getter and setter for the property myTableView and backing it with an iVar named myTableView_. But in your case you have already defined an iVar named myTableView_.
Try connecting the UITableView as a property instead. A property will be backed by an instance variable with the form _yourProperty and have getter and setter generated automatically so #synthesize isn't really needed in this case.

UITableView with UISegmented control and checkmark accessory

I am a newbie in the world of Objective-C and iOS coding so I'll appreciate a little bit of help.
Here is my issue. I've got a UITableView with a UISegmentedControl. This one has 6 different segments which modify the content of the table by modifying an NSMutableArray. I managed to do that so I'm already pretty proud of me but still the newbie curse is back today. I want to implement checkmarks in order to select cells and pass the cells' data to another UITableView. The first issue is that I've got my checkmarks but I click on a different segment the data are updated but the checkmarks from the previous segment remain. How to address this problem.
Second what is the best way to pass data from all of the segment of this UITableView to another tableview by selecting the cells?
Here is my UITableViewController.h
#class MesExercicesViewController;
#protocol MesExercicesViewControllerDelegate <NSObject>
- (void) mesExercicesViewControllerDidCancel:
(MesExercicesViewController *) controller;
- (void) mesExercicesViewControllerDidSave:
(MesExercicesViewController *)controller;
#end
#interface MesExercicesViewController : UITableViewController {
NSMutableArray *exercicesList;
UISegmentedControl *segment;
}
- (IBAction)segmentChange;
#property (nonatomic, retain) IBOutlet UISegmentedControl *segment;
#property (nonatomic, weak) id <MesExercicesViewControllerDelegate> delegate;
- (IBAction)cancel:(id)sender;
- (IBAction)done:(id)sender;
#end
And here is the code of the UISegmentedControl in the UITableViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
exercicesList = [NSMutableArray arrayWithObjects:
#"A",#"A1",#"A2",#"A3",#"A4",#"A5",#"A6",#"A7", nil];
}
- (IBAction)segmentChange {
if (segment.selectedSegmentIndex == 0) {
exercicesList = [NSMutableArray arrayWithObjects:#"A",#"A1",#"A2",#"A3",#"A4",#"A5",#"A6", nil];
[[self tableView]reloadData];
} else if (segment.selectedSegmentIndex == 1) {
exercicesList = [NSMutableArray arrayWithObjects:#"C",#"C1",#"C2",#"C3",#"C4", nil];
[[self tableView] reloadData];
} else if (segment.selectedSegmentIndex == 2) {
exercicesList = [NSMutableArray arrayWithObjects:#"E",#"E1",#"E2",#"E3",#"E4",#"E5",#"E6",#"E7",#"F",#"F1", nil];
[[self tableView] reloadData];
} else if (segment.selectedSegmentIndex == 3) {
exercicesList = [NSMutableArray arrayWithObjects:#"I",#"I1",#"I2",#"I3",#"I4",#"I5",#"I6",#"I7",#"I8",#"J", nil];
[[self tableView] reloadData];
} else if (segment.selectedSegmentIndex == 4) {
exercicesList = [NSMutableArray arrayWithObjects:#"L",#"M",#"M1",#"N",#"N1", nil];
[[self tableView] reloadData];
} else if (segment.selectedSegmentIndex == 5) {
exercicesList = [NSMutableArray arrayWithObjects:#"R",#"S",#"T",#"U",#"V",#"W",#"X",#"Y",#"Z", nil];
[[self tableView] reloadData];
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:[tableView indexPathForSelectedRow] animated:NO];
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
if (cell.accessoryType == UITableViewCellAccessoryNone) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
//reflect selection in data model
}else if (cell.accessoryType == UITableViewCellAccessoryCheckmark) {
cell.accessoryType = UITableViewCellAccessoryNone;
//reflect the deselection in data model
}
Thank you very much for your help in advance
Firstly, in your cellForRowAtIndexPath set
cell.accessoryType = UITableViewCellAccessoryNone;
this way, whenever you reloadData on your tableView it will get rid of the check marks. You could do this when a new segment is tapped.
2nd Edit
Secondly, set up 2 complimentary methods - in didSelectRow and didDeselectRow. Create a NSMutableArray in your viewDidLoad and then add to it. So your didSelectRow would have:
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[mutableArray addObject:[exercisesList objectAtIndex:indexPath.row]];
}
and your didDeselectRow would have
(void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath
{
[mutableArray removeObject:[exercisesList objectAtIndex:indexPath.row]];
}
and as far as the checkmarks go, have you implemented this?
[[self tableView] setEditing:YES animated:YES];
Then you would use this mutableArray to populate the new table.
1st EDIT
Here is some extra detail for how to set the delegate
So lets call the VC that has your original table - OriginalTableViewController
and the VC with the new table that you want to populate from the mutableArray - NextTableViewController (best to stay away from the word 'new' at the start of any names...)
NextTableViewController.h - right after the # import < UIKit/UIKit.h>
#class NextTableViewController;
#protocol NextTableViewControllerDelegate
-(NSMutableArray*)sendThroughTheMutableArray;
#end
declare your delegate
#property (nonatomic, assign) id delegate;
NextTableViewController.m
#synthesize delegate;
Then, you may be familiar with making calls to self like - [self getThatArray]; its the same with a delegate, but you just make the call to delegate instead of self
This is assuming you've declared the myTablePopulatingArray in your h file:
if(delegate != nil)
{
myTablePopulatingArray = [[NSMutableArray Alloc] initWithArray: [delegate sendThroughTheMutableArray]];
}
Basically to this point we have just set up the delegate. We are saying, this is what I need. Who's up for it? Who will volunteer for this job. We put the if(delegate != nil) as a safety - but you are the one who will make sure there is a delegate, so you probably don't really need it
Now for the delegate itself - you only need 2 things:
in your OriginalTableViewController.h file
#import "NextTableViewController.h"
#class DetailViewController;
OriginalTableViewController
in your OriginalTableViewController.m file you must put the method that you declared earlier
-(NSMutableArray*)sendThroughTheMutableArray
{
return mutableArray;
}
so this mutableArray is now ready to populate your tableView.

UITableView/UITabBarController: trying to figure out a method to pass a variable to my destination controller when a row is selected

I am using a UITableView that points to a UITabBarController to display a series of UIWebViews within these tabs.
I would like define a string to be used to construct a URL for each tab based on the item selected. The issue I am facing is how to pass the URL to the StateTrendViewController controller.
StateTableViewController.h
#import <UIKit/UIKit.h>
#interface StateTableViewController : UITableViewController
{
NSArray *StateList;
}
#property (nonatomic, retain) NSArray *StateList;
- (void) buildStateList;
#end
StateTableViewController.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [StateList count];
}
- (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];
}
NSInteger rowNumber = indexPath.row;
NSString *stateName = [StateList objectAtIndex:rowNumber];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.textLabel.text = stateName.capitalizedString;
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[tableView deselectRowAtIndexPath:indexPath animated:YES];
NSInteger rowNumber = indexPath.row;
NSString *stateName = [StateList objectAtIndex:rowNumber];
[[self.navigationController.viewControllers objectAtIndex:2] setTitle:stateName.capitalizedString];
}
StateTrendViewController.h
#import <UIKit/UIKit.h>
#interface StateTrendViewController : UIViewController
{
IBOutlet UIWebView *StateTrendView;
IBOutlet NSString *ViewURL;
}
#property (nonatomic, retain) UIWebView *StateTrendView;
#property (nonatomic, retain) NSString *ViewURL;
#end
StateTrendViewController.m
#import "StateTrendViewController.h"
#implementation StateTrendViewController
#synthesize StateTrendView;
#synthesize ViewURL;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void) viewWillAppear:(BOOL)animated
{
NSString *baseURL = #"https://www.google.com/search?q=";
NSString *state = #"test";
NSString *fullURL = [baseURL stringByAppendingString:state];
NSURL *url = [NSURL URLWithString:fullURL];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url]; [StateTrendView loadRequest:requestObj];
}
I need to replace the static setting with the sting passed to the controller using the ViewURL property I have setup:
NSString *state = #"test";
I am using a Storyboard in my project in Xcode 4.2.1. How should I go about passing that string value to my controller?
You override prepareForSegue, more detail is here
If all you are passing is a string, the simplest way might be to define a property on your the view controller you are presenting to hold the string. I notice you already have one, *ViewURL defined, but I'm not sure if that's what you've setup for this specific task or if that is already intended for something else.
Based on the code you've shared, I'm assuming that in your didSelectRowAtIndexPath in your table controller, the controller you are setting the title, and presumably later pushing, is an instance of a StateViewController:
[[self.navigationController.viewControllers objectAtIndex:2] setTitle:stateName.capitalizedString];
If this line does indeed reference an instance of StateTrendViewController, you would assign your string in the same way you're assigning title. This needs to be set before you segue into the new view controller (I don't see that code):
[[self.navigationController.viewControllers objectAtIndex:2] setViewURL:#"MyPassedString"] //assign custom property
When your view controller appears on screen, it will have it's property ViewURL already set.
Also note that your naming style for instance variables is not a standard cocoa convention, ivars beginLowerCase. Additionally, it is unusual and may not work to push a TabBar controller inside an existing nav controller, presumably from table view view controller inside an existing nav controller. Typically a TabBar is considered a top-level navigational construct, and you may wish to rethink your architecture accordingly.

Table view as an object in a view - how to initialize with an array of data?

My goal is to have something like a "select" option in a HTML form, but now in my app. After doing research it's probably best to do this with a table view. I though of the picker view, but the fixed height is too big.
With the interface builder I simply placed a table view on my subclass of UIViewController.
How do I fill the Table view with options? I've seen many tutorials, but those are all for having a UITableView as their own class and filling up the entire screen. In my application this is just a small piece of the entire form.
What a nightmare to create a relatively simple thing like a table view. It either crashes or I get a table view that covers my entire view and that is not filled with anything.
The variable countryTable is connected to the object in the interface builder.
Frustrated after a hard day of work. Anyone got the complete working code? That would be great. I already had a great look at apple's explenation AND various tutorials, but I can't figure it out.
I've tried multiple things, but this is my current code:
#interface myView: UIViewController
{
NSArray *countryArray;
IBOutlet UITableView * countryTable;
}
#property (nonatomic, retain) UITableView *countryTabel;
#end
and in my .m file
#implementation myView
#synthesize countryTable;
- (void)loadView
{
self.countryTable.dataSource = self;
}
- (void)viewDidLoad
{
NSArray *array = [[NSArray alloc] initWithObjects:#"test1", #"test2",
#"test3",nil];
self.countryTable = array;
[array release];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void) dealloc
{
[countryTable release];
[super dealloc];
}
#pragma mark -
#pragma mark Table View Data Source Methods
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.countryTable count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [countryTable objectAtIndex:row];
return cell;
}
#end
You are on the right track. If you were to use a UITableViewController subclass, you would obviously have a full screen table view by default. Going the route of using a UIViewController subclass with a UITableView as a subview in the UIViewController's view is the right way to go. A few things that you will need to address are:
1) In the UIViewControllers header file you will need to add <UITableViewDatasource, UITableViewDelegate> as your view controller is responsible for fill implementing this functionally.
2) In viewDidLoad:, set self.contryTable.delegate = self; and self.countryTable.datasource = self;
The following protocol methods need to be implemented like so:
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return countryArray.count;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *SimpleTableIdentifier = #"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:SimpleTableIdentifier] autorelease];
}
NSUInteger row = [indexPath row];
cell.textLabel.text = [countryArray objectAtIndex:row];
return cell;
}
Hope this helps.