How to access objects inside an array object - ios

I am creating an application for IOS and am struggling with accessing an object inside an array i have made for display on the table view cell.
This is the code i have used to add the object to the array every time the loop cycles through.
for (int i = 0; i < [parsedArray count]; i++) {
HPTBusStops *busStops = [[HPTBusStops alloc] init];
NSArray *informationArray = [parsedArray objectAtIndex:i];
busStops.busStopNumber = [informationArray objectAtIndex:0];
busStops.busStopName = [informationArray objectAtIndex:1];
busStops.latitude = [informationArray objectAtIndex:2];
busStops.longitude = [informationArray objectAtIndex:3];
[self.busStopsHolder addObject:busStops];
}
The HPTBusStops class is obviously custom, and later in the master view controller, i am tring to re-access these properties through the busStopsHolder array, when programming the cell, in this part:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
HPTBusStopsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BusStopCell" forIndexPath:indexPath];
return cell;
}
I am honestly very unsure of how to access the busStops object's properties through the busStopHolder's array.
Any help would be appreciated
Thanks
Hamish

It looks to me like you might have an issue with scope...
You'll need to make "busStopsHolder" a #property of the class containing the for loop and instantiate that class as an instance variable in your Master View Controller.
in your class, say MyInfoClass.h:
#property (strong, nonatomic) NSMutableArray *busStopsHolder;
in MyInfoClass.m:
synthesize busStopsHolder;
Make sure you have initialized your busStopsHolder array in MyInfoClass...
(id) init {
busStopsHolder = [[NSMutableArray alloc] init];
}
Then in your master view controller .h:
#import "MyInfoClass.h"
#interface myMastserViewController : UIViewController {
MyInfoClass *infoClass;
}
Then...
- (void) viewDidLoad {
infoClass = [[MyInfoClass alloc] init];
[infoClass methodToLoadBusStops];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
HPTBusStopsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BusStopCell" forIndexPath:indexPath];
HPTBusStop *busStop = [[infoClass busStopsHolder] objectAtIndex:indexPath.row];
[[cell textLabel] setText:[busStop busStopName]]
return cell;
}

An oversimplified way to do this is as follows:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
HPTBusStopsTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"BusStopCell" forIndexPath:indexPath];
HPTBusStops *busStops = yourSourceArray[indexPath.row];
cell.textLabel.text = busStops.name;
return cell;
}
If your tableView has one section, you can use the tableView's indexPath.row property to determine which index you're dealing with, use that as the index to access the relevant object in your source array, and then customize the cell based on the specific object at that index. In the example code I just assumed there was a name property on the busStops object for example purposes.
Make sure in your numberOfRowsInSection method you set the number of rows as the number of objects in your source array, whatever that is.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return yourSourceArray.count;
}

Related

Table View's cellForRowAtIndexPath: not being called

For some reason, my table view's cellForRowAtIndexPath:(NSIndexPath *)indexPath method isn't being called. Here is my code:
- (void)viewDidLoad {
[super viewDidLoad];
messages = [[NSMutableArray alloc]init];
chatTable = [[UITableView alloc]init];
chatTable.delegate = self;
chatTable.dataSource = self;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Called Count %i",messages.count);
return messages.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"Was Called");
static NSString *cellId = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellId];
NSDictionary *message = [messages objectAtIndex:indexPath.row];
NSString *mess = [message objectForKey:MSChatMessage];
cell.textLabel.text = mess;
return cell;
}
Here's what I've done:
Linked the datasource and delgate
Linked the IBOutlet for the table view
Set the cell identifier to Cell
Made sure the array was not nil (the log gives the right number)
Tried using a static NSMutableArray, and it worked, but once i went back to my dynamic array it did not
"Was Called" never appears in the log
You initialized message:
messages = [[NSMutableArray alloc]init];
But then you never populated the array.
cellForRowAtIndexPath delegate is called based on the datasource array count.
Make sure the following line:
NSLog(#"Called Count %i",messages.count);
prints a count greater than 0
When you have linked the UITableView from xib or storyboard as IBOutlet. Why are you creating the UITableView again "chatTable = [[UITableView alloc]init]"
Remove this line from the code and try.
Also set the delegate and datasource from the Interface Builder and remove chatTable.delegate = self; & chatTable.dataSource = self;
Also observed that you are creating the message in viewDidLoad which is not proper. Try to print this count of messages, it should not be zero.
i hop these helps..
in .h file..
NSMutableArray * messages;
in .m file..
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialization of NSMutableArray.
messages = [[NSMutableArray alloc]init];
}
and make sure its not nil in here..
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSLog(#"Called Count %i",messages.count);
return messages.count;
}

Populate UI Table View with array of strings

I can't find a simple, concise answer anywhere and I refuse to believe that XCode makes things as hard as other tutorials I've found out there...
Say I have the following array
NSArray* days = [NSArray arrayWithObjects:#"Sunday",#"Monday",#Tuesday",#"Wednesday",#"Thursday",#"Friday",#"Saturday",nil];
I have a UI Table View, table_Days, that I would like to simply show the items from my array. What is the proper way to go about populating my table?
Here's my full explanation, starting with a case extremely similar to yours:
http://www.apeth.com/iOSBook/ch21.html#_table_view_data
So suppose days is stored as an instance variable accessed through a property self.days. Then set self as the table view's datasource and use this code:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (!self.days) // data not ready?
return 0;
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section {
return [self.days count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell =
[tableView dequeueReusableCellWithIdentifier:#"Cell"
forIndexPath:indexPath];
cell.textLabel.text = (self.days)[indexPath.row];
return cell;
}
You should populate your table view using the data source methods. Returning the count of the array for the number of rows.
If you need to detect when a user taps on a cell you can use the delegate methods.
#interface ViewController<UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, copy) NSArray *days;
#property (nonatomic, strong) UITableView *tableDays;
#end
#implementation ViewController
-(void)viewDidLoad
{
[super viewDidLoad];
UITableView *tableDays; // Set this up
[tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:#"Cell"];
tableDays.delegate = self;
tableDays.dataSource = self;
[self.view addSubview:tableDays];
self.tableDays = tableDays;
self.days = #[#"Sunday", #"Monday", #"Tuesday", #"Wednesday", #"Thursday", #"Friday", #"Saturday"];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.days count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
cell.textLabel.text = self.days[indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *day = self.days[indexPath.row];
NSLog(#"Day tapped: %#", day);
}
#end
You should consider using a UITableViewController if you just want to show a table view.
Note that its better practice to use camel case for variables.

iOS - Simple Table Sections with Array Data

I'm just starting with iOS/Xcode and have been Googling/Youtubing for an hour and can't find a matching tutorial. All I'm trying to do right now is display a table with a list of exercises (rows) that are grouped by bodypart (sections). The bodypart sections will never change, but the user will be able to add a custom exercise to a bodypart.
Now, I'm assuming that I need an array for the sections and also an array for exercises...creating those is simple enough. I'm running into a problem assigning exercises to specific sections. Here's an example of the faulty code that when rendered, displays both exercises under both sections...also there aren't any section names being generated in the table so I'm not sure where that comes into play either.
Here's a screenshot of the result (as a side note, not sure why my nav controller isn't rendering): http://i.imgur.com/icoJgEq.jpg
Create the individual items:
#property NSString *exerciseName;
#property NSString *exerciseCategoryName;
Create/Allocate the arrays:
#property NSMutableArray *exerciseCategories;
#property NSMutableArray *exercises;
self.exerciseCategories = [[NSMutableArray alloc]init];
self.exercises = [[NSMutableArray alloc]init];
Fill the arrays with some default data:
- (void)loadInitialData {
FNTExerciseCategories *category1 = [[FNTExerciseCategories alloc]init];
category1.exerciseCategoryName = #"Chest";
[self.exerciseCategories addObject:category1];
FNTExerciseCategories *category2 = [[FNTExerciseCategories alloc]init];
category2.exerciseCategoryName = #"Biceps";
[self.exerciseCategories addObject:category2];
FNTExercises *exercise1 = [[FNTExercises alloc]init];
exercise1.exerciseName = #"Bench Press";
[self.exercises addObject:exercise1];
FNTExercises *exercise2 = [[FNTExercises alloc]init];
exercise2.exerciseName = #"Barbell Curl";
[self.exercises addObject:exercise2];
}
Load the data:
[self loadInitialData];
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [self.exerciseCategories count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [self.exercises count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
MFTExercises *exercise = [self.exercises objectAtIndex:indexPath.row];
cell.textLabel.text = exercise.exerciseName;
return cell;
}
Thank you very much to anybody that can chime in!
Actually in tableView:numberOfRowsInSection: you are returning the count of the entire exercises array. So with your sample data you would have two rows per section. Try making an array of exercises for every section and then code something like the following:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
if (section == 0) {
return [self.chestExercises count];
}
else if (section == 1) {
return [self.bicepsExercises count];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
MFTExercises *exercise;
if (indexPath.section == 0) {
exercise = [self.chestExercises objectAtIndex:indexPath.row];
}
else if (indexPath.section == 1) {
exercise = [self.bicepsExercises objectAtIndex:indexPath.row];
}
cell.textLabel.text = exercise.exerciseName;
return cell;
}
In this case the chestExercises array would only contain the "Bench Press"-exercise and the bicepsExercises would only contain the "Barbell Curl"-exercise. So you would get one row per section.
For achieving that the sections have titles you would need to implement the method
- (NSString *)tableView:(UITableView *)aTableView titleForHeaderInSection:(NSInteger)section {
return [self.exerciseCategories objectAtIndex:section];
}
which gives the sections the title according to the names stored in the array.
A more sophisticated way to build your datasource would be to create a NSDictionary with the section names as the keys (bodyparts) and the values being arrays containing the exercises for the bodypart. For instance if your categories are merely strings you could build such a dictionary with your sample data (for the purpose of demonstration I added another exercise):
FNTExerciseCategories *category1 = [[FNTExerciseCategories alloc]init];
category1.exerciseCategoryName = #"Chest";
[self.exerciseCategories addObject:category1];
FNTExerciseCategories *category2 = [[FNTExerciseCategories alloc]init];
category2.exerciseCategoryName = #"Biceps";
[self.exerciseCategories addObject:category2];
FNTExercises *exercise1 = [[FNTExercises alloc]init];
exercise1.exerciseName = #"Bench Press";
FNTExercises *exercise2 = [[FNTExercises alloc]init];
exercise2.exerciseName = #"Barbell Curl";
FNTExercises *exercise3 = [[FNTExercises alloc]init];
exercise3.exerciseName = #"Another Exercise";
// the instance variable self.exercises is a NSMutableDictionary now of course
self.exercises = [[NSMutableDictionary alloc] init];
exercises[category1.exerciseCategoryName] = #[exercise1];
exercises[category2.exerciseCategoryName] = #[exercise2, exercise3];
The advantage here is that you now have one dictionary containing all arrays that contains all your data. So as you're adding more data you don't have to change your implementation of the tableView datasource. BTW I am using Modern Objective-C syntax for the dictionary and arrays.
Having created a dictionary like that you could then simply implement your table view data source like so:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
// This gives the name of the category at the current section.
// It is then used as a key for the dictionary.
NSString *currentCategory = [[self.exerciseCategories objectAtIndex:section] exerciseCategoryName];
return [self.exercises[currentCategory] count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ExercisePrototypeCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSString *currentCategory = [[self.exerciseCategories objectAtIndex:indexPath.section] exerciseCategoryName];
MFTExercises *exercise = [self.exercises[currentCategory] objectAtIndex:indexPath.row];
cell.textLabel.text = exercise.exerciseName;
return cell;
}
Using a NSDictionary may or may not benefit your app but you don't have to create an array as instance variable for every body part you have. It may also be more easy to save a single dictionary to disk for persistence.
First of all, you should practice it with WWDC UITableView section. There are many source code that uses UITableView, UICollectionView and UIScrollView.
What you need in that code is you need to return section header for exerciseCategories, you only defined number of section in - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView this delegate function but you are returning all nil value for the section header at the moment.
- (NSString*)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
FNTExerciseCategories *category = [self.exerciseCategories objectAtIndex:section];
return category. exerciseCategoryName;
}
this will display your section. but you need to think about the structure of your data because right now you are not returning correct number for each section you are just returning [self.exercises count] for all section.
And to render the UINavigationController, you need to push the view rather than present view as modal.
[self.navigationController pushViewController:exerciseView animated:YES];

Advice on creating table with dynamic data in IOS

I am trying to create a table with dynamic data and I'm kind of stuck. Here is how my data is structured :
NSMutableArray *bigArray;
bigArray has many NSDictionary items.
each items has only one entry.
sectionName is the key, NSMutableArray is the value.
There are many objects in the value NSMutableArray.
I tried to explain this as simple as I could, here is the part where I'm stuck.
//easy
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return [bigArray count];
}
//medium
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
// Return the number of rows in the section.
return [[[[bigArray objectAtIndex:section] allValues] objectAtIndex:0] count];
}
I can't figure out this part how to implement this method based on my current data structure :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:#"MyCell"];
MyObject *obj = //Need this part
cell.textLabel.text = obj.name;
return cell;
}
Simply put, I'm trying to insert dynamic sections with dynamic data. I'm looking for advice from more experienced developers, how would you tackle this?
Assuming I understood well how your data is structured, here's how I would do it:
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"MyCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"MyCell"];
}
//this will get you the dictionary for the section being filled
NSDictionary *item = [bigArray objectAtIndex:indexPath.section];
// then the array of object for the section
NSMutableArray *mutableArray = [item objectForKey:#"sectionName"];
//you then take the object for the row
MyObject *obj = [mutableArray objectAtIndex:indexPath.row];
cell.textLabel.text = obj.name;
return cell;
}
Don't forget to set the reuse identifier for the cell prototype in the attributes inspector

How to populate UITableView with plist

I have a simple UITableView that I'd like to populate using a plist file. I have followed a few tutorials but they all seem to over complicate the process and in the end I end up getting errors or my app simply does not work.
I'm using a window based application.
Cheers,
Sam
To load the file :
thearray = [NSArray arrayWithContentsOfFile:thePath];
Then you need to set your controller as the data source and delegate for the table view and implement at least :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [thearray count];
}
// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell* cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
// assuming your array contains only simple strings :
cell.textLabel.text = [thearray objectAtIndex:indexPath.row];
return cell;
}
This doesn't use the "reuse" of cells which is important if your list is big.

Resources