Selecting Variable Dynamically - ios

Hello and thank you for your time. Im fairly new to IOS/Objective C.
I have multiple variables setup globally at the top of my viewcontroller.
NSMutableArray * A;
NSMutableArray * B;
NSMutableArray * C;
Now when someone selects a cell in a tableview I would like to use the name of that cell to select one of the global variables. I found something for doing this with viewcontrollers, but I need something for misc variables as well. I am reffering to:
id myNewController = [[NSClassFromString(selected) alloc] init];
[[self navigationController] pushViewController:myNewController animated:YES];
So it would be something like this:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Save text of the selected cell:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
stringVariable = cell.textLabel.text;// value=A,B or C
// match string to array and load that array.
??
}
Thanks in advance for any help, and sorry if this has been asked but I couldn't find anything that worked so as a last resort im asking for help :)

You may be better off storing your arrays as keys on a dictionary, instead of as individual fields. For example:
NSDictionary* dictionary;
dictionary = #{
#"A": [[NSMutableArray alloc] init],
#"B": [[NSMutableArray alloc] init],
#"C": [[NSMutableArray alloc] init]
};
Then when your row is selected, you could lookup the array by key:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString* key = cell.textLabel.text;// value=A,B or C
NSMutableArray* array = dictionary[key];
....

Related

UITableView not reloading correctly

I've been having this problem a lot where the table view either doesn't load the cells the first time or displays temporary labels. In both cases, when the table is loaded a second time (by another button in which I force it to reload or by going to the previous view in the app and going back to the table) everything shows up as it was supposed to.
Im using [table reloadData] to reload the table in the viewDidAppear: method as it didn't work in the viewDidAppear: method and in another case I put it in a button action.
I'm also using this method to set the label of the cell that I have placed in the storyboard:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [contactsTableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}
UILabel *label = (UILabel *)[cell viewWithTag:1001];
label.text = [Array3 objectAtIndex:indexPath.row];
return cell;
}
EDIT
I declare the array below the implementation like:
NSMutableArray * Array3;
After that in the ViewDidLoad method I declare the rest of the array:
Array3 = [NSMutableArray arrayWithObjects: nil];
Then I load the elements in the array by calling a function within the ViewDidLoad method to fill the array with elements.
EDIT 2
Showing more of how I populate the array
- (void)viewDidLoad {
[super viewDidLoad];
Array3 = [NSMutableArray arrayWithObjects: nil];
[self loadArray];
}
- (void) loadArray
//populate array in here.
// I use the add object method
// [Array3 addobject:object];
{
Good news first: Your method cellForRowAtIndexPath is correct.
There is no need to invoke reloadData in neither -viewDidAppear: nor -viewWillAppear. This remark may not hold true if you modify the content of Array3 while your view is covered, which is a special case.
It is not a matter of where you define your method, but where you invoke it. A reasonable place to populate the content of Array3 is in
required init(coder aDecoder: NSCoder!)
or
override func viewDidLoad()
Pitfalls
Additionally, you need all your delegate methods (numberOfSectionsInTableView, numberOfRowsInSection, cellForRowAtIndexPath) to be returning consistent values, in accordance to your array. A simple technique is to use the number of entries in the array to drive numberOfRowsInSection.
When to use reloadData?
A typical use of reloadData is shown below:
- (void)loadArray {
//populate array in here.
...
[self.tableview reloadData]; // Possibly postpone to main thread
}
Give the cell identifier unique for example you can
NSString *cellIdentifier =[NSString stringWithFormate:#"%d",indexPath.row];
Maybe this will help you...
I think the Array3 is nil When the first load.
I believe that in your initial set up for Array3 you must allocate this variable to memory to then be used in a different function, like the tableView:cellForIndexPath:
Therefore instead of Array3 = [NSMutableArray arrayWithObjects: nil]; you would use Array3 = [[NSMutableArray alloc] init];
Since you're leaving it as an empty array on this line of code, you would not use [[NSMutableArray alloc] initWithObjects: nil]; because it is literally the same deal

NSDictionary syntax explanation

I have UITableView and NSDictionary. It populated like follow:
currentAlbumData = [album tr_tableRepresentation];
Where albums is simple NSObject class:
// h.file
#interface Album : NSObject
#property (nonatomic, copy, readonly) NSString *title, *artist, *genre, *coverUrl, *year;
-(id)initWithTitle:(NSString*)title artist:(NSString*)artist coverUrl:(NSString*)coverUrl year:(NSString*)year;
//m.file
-(id)initWithTitle:(NSString *)title artist:(NSString *)artist coverUrl:(NSString *)coverUrl year:(NSString *)year{
self = [super init];
if (self){
_title = title;
_artist = artist;
_coverUrl = coverUrl;
_year = year;
_genre = #"Pop";
}
return self;
};
And tr_tableRepresentation is category of Album class, returning NSDictionary:
//h.file
#interface Album (TableRepresentation)
- (NSDictionary*)tr_tableRepresentation;
#implementation Album (TableRepresentation)
//.m file
- (NSDictionary*)tr_tableRepresentation
{
return #{#"titles":#[#"Artist", #"Album", #"Genre", #"Year"],
#"values":#[self.artist, self.title, self.genre, self.year]};
}
That is the code i take from tutorial, so, in following lines we populate tableView data with NSDictionary values:
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
//... Cell initialization code
cell.textLabel.text = currentAlbumData[#"titles"][indexPath.row];
cell.detailTextLabel.text = currentAlbumData[#"values"][indexPath.row];
}
Now I'm stuck. because I'm getting confused when i see syntax like that.
cell.textLabel.text = currentAlbumData[#"titles"][indexPath.row];
cell.detailTextLabel.text = currentAlbumData[#"values"][indexPath.row];
What exactly is going on here? What this lines of code do? I can understand that we accessing #"titles" and #"values" somehow, could you please rewrite that lines in more readable manner, without square brackets?
And how could we even get #"titles" and #"values" using just indexPath (integer number)? That may sound kind of silly, but I'm not get it. I thought we have to put string as a parameter to access NSDictionary values, not an integer.
It is just a short way of writing code:
currentAlbumData[#"titles"][indexPath.row] is same asĀ [[currentAlbumData objectForKey:#"titles"] objectAtIndex:indexPath.row]. Here, currentAlbumData is a dictionary. You get it's object for key titles, which is (supposedly) an array. Then you get the object at index indexPath.row of this array.
titles is the key for an NSArray of NSStrings. So is values.
currentAlbumData[#"titles"] asks the dictionary for the value at the titles keypath. This returns an NSArray that is indexed by NSUIntegers, such as indexPath.row.
Titles is an array so to get value at particular index you can use
cell.textlabel.text = [[currentAlbumData valueForKey:#"titles"] objectAtIndex:indexPath.row];
If you find this confusing then better store Titles inside an array and then use it below
NSArray *titles = [currentAlbumData valueForKey:#"titles"];
cell.textlabel.text = [titles objectAtIndex:indexPath.row];

Filter Array into sections

I am building an IOS app based on data within an array - I'm struggling with filtering data into rows - a snippet of my array is as follows -
ARRAY Data / Array -
sightsObject *sight2 = [[sightsObject alloc] initWithsiteTitle:#"The Beatles Homes" siteSection:#"beatles" siteType:#"Take a glimpse of the fab 4's childhood homes.." siteSubTitle:#"" siteDescription:#"" siteMapUrl:#"" sitePic:#"fabs"];
sightsObject *sight3 = [[sightsObject alloc] initWithsiteTitle:#"The Beatles Gig Venues" siteSection:#"beatles" siteType:#"" siteSubTitle:#"Its not all about the Cavern..." siteDescription:#"" siteMapUrl:#"" sitePic:#"fabs"];
sightsObject *sight4 = [[sightsObject alloc] initWithsiteTitle:#"The Beates Locations" siteSection:#"beatles" siteType:#"" siteSubTitle:#"Stawberry Fields, Penny Lane, Palm House..." siteDescription:#"" siteMapUrl:#"docks" sitePic:#"fabs"]
sightsObject *sight5 = [[sightsObject alloc] initWithsiteTitle:#"Albert Dock" siteSection:#"dock" siteType:#"" siteSubTitle:#"" siteDescription:#"" siteMapUrl:#"" sitePic:#""];
sightsObject *sight6 = [[sightsObject alloc] initWithsiteTitle:#"Keiths Wine Bar" siteSection:#"Restaurants" siteType:#"" siteSubTitle:#"Classic Eatery on Lark Lane" siteDescription:#"" siteMapUrl:#"" sitePic:#""];
self.sightsArray = [NSArray arrayWithObjects: sight2, sight3, sight4, sight5, sight6,nil];
SightsObject.H
The Header for the SightsObject os as follows -
#import <Foundation/Foundation.h>
#interface sightsObject : NSObject
#property(strong)NSString *siteTitle;
#property(strong)NSString *siteSection;
#property(strong)NSString *siteType;
#property(strong)NSString *siteSubTitle;
#property(strong)NSString *siteDescription;
#property(strong)NSString *siteMapUrl;
#property(strong)UIImage *sitePic;
-(id)initWithsiteTitle:( NSString *)siteTitleD siteSection:(NSString *)siteSectionD siteType:(NSString *)siteTypeD siteSubTitle:(NSString *)siteSubTitleD siteDescription:(NSString *)siteDescriptionD siteMapUrl:(NSString *)siteMapUrlD sitePic:(NSString *)sitePicD;
#end
ROWS
I was unsure how to count the amount of data rows that apply to each section - so this is currently hardcoded -
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 8;
}
FILTERING DATA INTO TABLE CELLS
My issue is that I now dont know how to filter the data into rows - I currently have below (i have two cell types in my tableview) - when run the code displays the relevant data in the correct cells - but repeats the same data for every section - how can I filter it correctly?
-(UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier =#"sightsCell";
static NSString *CellIdentifierH =#"headerCell";
NSString * intro = #"intro";
NSString * ArtNoP = #"lower";
sightsObject *b = [self.sightsArray objectAtIndex:indexPath.row];
tableView.tableFooterView = [[UIView alloc] initWithFrame:CGRectZero];
UITableViewCell *cell;
if ([b.siteSection isEqualToString:intro]) {
cell= [tableView dequeueReusableCellWithIdentifier:CellIdentifierH forIndexPath:indexPath];
HeaderCell *cellHead = (HeaderCell *)cell;
cellHead.selectionStyle = UITableViewCellSelectionStyleNone;
cellHead.sightsText.text = b.siteTitle;
cellHead.textLabel.backgroundColor=[UIColor clearColor];
return cellHead;
}
else{
cell= [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
sightsCell *cellSights = (sightsCell *)cell;
cellSights.selectionStyle = UITableViewCellSelectionStyleNone;
cellSights.sightsTitle.text = b.siteTitle;
cellSights.sightsSubTitle.text = b.siteSubTitle;
cell.textLabel.backgroundColor=[UIColor clearColor];
return cellSights;
}
}
I'd change what you're doing. Rather than have one array with a big list of items and a static count of the sections I'd have an array which contains sections, and each section would be another array containing the row items. This could either be created manually (your configuration code would change) or automatically (by iterating over your existing sightsArray and running various predicates on it. The choice really depends on how many items you have and how many / where they will come from in the future.
Once you have that, the number of sections is self.sightsArray.count and the number of rows in each section is [self.sightsArray[section] count] and the row for a section is:
sightsObject *b = self.sightsArray[indexPath.section][indexPath.row];
I would also use indexPath.row == 0 as the indication that you should have an intro row because to organise the sections automatically I would keep all of the siteSection values the same for each section.

How to get the values of selected cells of a UITableView in one string

i'm pretty sure this is really simple. But i can't get to make this work. I have a UITableView where i display dynamically a list of facebook friends, thanks to their FBID. Basically, i would like to return the FBIDs of the friends i selected, in one string separated with commas. If possible, in a IBAction, so i can pass them into parameters of a php.
For example, let's pretend i have a list of 4 friends, A B C D, and their ids are 1,2,3,4.
If i select A and C, i would like to have a string which says 1,3.
All i managed to do is to display the id of the friend i select, one at a time.
Here's my code :
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
rowcount = [[tableView indexPathsForSelectedRows] count];
indexer = [idFriends objectAtIndex:indexPath.row];
aapell = [NSString stringWithFormat:#"%#", indexer];
NSMutableString * arrayIds = [[NSMutableString alloc] init];
[arrayIds appendString:aapell];
NSLog(#"ids: %#", arrayIds);
}
Thank you in advance, i'm sure this is not complicated.
-(IBAction)gatherFBIds
{
NSString *listOfFacebookIDs = #"";
NSArray *indexPathArray = [self.tableView indexPathsForSelectedRows];
for(NSIndexPath *index in indexPathArray)
{
//Assuming that 'idFriends' is an array you've made containing the id's (and in the same order as your tableview)
//Otherwise embed the ID as a property of a custom tableViewCell and access directly from the cell
//Also assuming you only have one section inside your tableview
NSString *fbID = [idFriends objectAtIndex:index.row];
if([indexPathArray lastObject]!=index)
{
listOfFacebookIDs = [listOfFacebookIDs stringByAppendingString:[fbID stringByAppendingString:#", "]];
}
else
{
listOfFacebookIDs = [listOfFacebookIDs stringByAppendingString:fbID];
}
}
NSLog(#"Your comma separated string is %#",listOfFacebookIDs);
//Now pass this list to wherever you'd like
}
The problem is that you are not using the information in indexPathsForSelectedRows. That is telling you all the selected rows. Instead, you are just looking at indexPath.row, which is the one row most recently selected.
What you need to do is cycle through indexPathsForSelectedRows and gather up the info for every row that is currently selected (I'm assuming you've enabled multiple selection here).
Use the following code to get the selected rows in a table view. :)
NSArray *selectedRows=[tableView indexPathsForSelectedRows];
NSMutableArray *rownumberArray=[[NSMutableArray alloc]init];
for (int i=0; i<selectedRows.count; i++) {
NSIndexPath *indexPath = [selectedRows objectAtIndex:i];
NSInteger row = indexPath.row;
NSNumber *number = [NSNumber numberWithInteger:row];
[rownumberArray addObject:number];
}
// rownumberArray contains the row numbers of selected cells.

How to populate tableview controller with text input

I have created a table view controller with a UITextField on it. How can I populate the tableview controller cell of the input text that came from the UITextField. I tried the following but it seems the array is empty or being emptied
- (IBAction)endingInput:(id)sender{
[sender resignFirstResponder];
//send the message to the table cell
NSMutableArray *history = [[NSMutableArray alloc] init];
[history addObject:[NSString stringWithFormat:#"%#",self.chatMessageField.text]];
[self.chatHistory addObject:history];
[myTableView reloadData];
//push the message to server
[self initiateMessageSending:self.chatMessageField.text];
chatMessageField.text = #"";
[history release];
}
On my cellForRowAtIndex method;
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
// Configure the cell...
if(cell == nil){
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
if(tableView == self.myTableView){
cell.textLabel.text = [chatHistory objectAtIndex:indexPath.row];
}
return cell;
I have set a break point but it doesn't pass there. I suspect my array is empty.
Likewise, where is the best place to call the reloadData method?
Also, chatHistory is private member, is there a way to initialize it like [[self.chatHistory alloc] init]; ?
I know its a common question but I've been haggling with this for sometime now.
I think you have forgotten to alloc and init your chatHistory
- (void)viewDidLoad
{
self.chatHistory = [[NSMutableArray alloc] init];
}
If you aren't initializing chatHistory it doesn't even exist...never mind being empty! (I'm not clear what "private member" means here.)
If you log the value of chatHistory, you'll see for sure whether it is nil or empty.
The other problem I see is that you're trying to load chatHistory with other (history) arrays but then use its content as a string. You should decide whether it's going to be an array of arrays or an array of strings and then stay consistent.
(Also [[self.chatHistory alloc] init]; isn't valid syntax for creating a new object. Look at an Objective-C language reference for the right way.)

Resources