Load Data depending on what TableView Cell was selected - iphone

I have a table view. I want my app to work like the "Contacts" app on the iPhone. When you select a person in the app, it goes to a view that has the users name and phone number. and it doesnt matter which cell is selected, it always goes to the same view, but with different data. How can i achieve the same thing? I want one view controller and i want each cell to load certain data onto the presented view controller! And i would like to use NSUserDefaults (if possible). Any Help would be great, Thank You!
P.S. i know this is kind of a broad question, but im unsure where to find an answer i have searched and searched. Thanks again!

I want one view controller and i want each cell to load certain data
onto the presented view controller!
No problem. User taps on cell, your table's delegate gets a -tableView:didSelectRowAtIndexPath: message. Let's say the table's delegate and data source are both the view controller that manages the table (because that's a pretty common setup). So the view controller takes a look at the index path for the cell, grabs the associated data from wherever it keeps its data, instantiates the detail view controller with the data connected to the tapped cell, and pushes it.
The part that you're probably missing is some sort of model that stores the data displayed in the table. The view controller for the table needs to know about the model because it's the data source for the table. It already needs to know where to find enough data to configure each cell in the table. If you use that same model to store the detail data, you'll be able to use it to configure the detail view controller.
Example: Let's say you have a table with just one section. A simple model for that table could be an array of dictionaries. When your table view controller needs to populate a cell, it uses the row of the index path as an index into the array to get a dictionary, and it uses that to set up the cell. Exactly the same thing happens when the user taps a cell: you use the row from the index path to get the right dictionary from the array, and you use that to set up the detail view controller. You could even just pass the whole dictionary to the detail view controller and let the detail view controller get what it needs. That way the table view controller doesn't have to worry about exactly which details the detail view controller displays.

You create an array of names (strings) and display those names in your table view.
Then once a name was selected you save it in NSUserDefaults as a string.
- (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath
{
NSString *selectedString = [namesArray objectAtIndex:[indexPath row]];
NSUserDefaults *infoSaved = [NSUserDefaults standardUserDefaults];
[infoSaved setObject:selectedString forKey:#"theName"];
[infoSaved synchronize];
[self performSegueWithIdentifier:#"segueToMoreInfo" sender:self];
}
Then at your second view controller you load the information from an NSDictionary that contains NSDictionary items.
-(void) loadData {
NSUserDefaults *infoSaved = [NSUserDefaults standardUserDefaults];
NSString *theName = [infoSaved objectForKey:#"theName"];
NSDictionary *currentNameToDisplay = [itemsDictionary objectForKey:theName];
// then you can set your labels with information in that NSDictionary item
[nameLabel setString:[currentNameToDisplay objectForKey:#"userName"];
[ageLabel setString:[currentNameToDisplay objectForKey:#"userAge];
}
That would be a simple basic structure.
You can save the main Names NSDictionary that contains the items into a plist file or even better save the dictionary in NSUserDefaults.
Hope that helps.

Related

Data Pass to UIPickerView inside of UITableViewCell

I have UITableView and there is a picker view inside every cell. User can change value of every picker separately.
I need to know that which cell's pickerView is changed. For example, when user move a picker I will know that, this is cell 3.
Is there any way to do that? It's not necessary to get instant changed values. We can store it on array than send when Go button clicked that is not related with tableview.
I would suggest to store an array of pointers to your picker views. So index 0 of your array would point to the picker view of table row 0, etcetera. Then, make sure your view controller is the delegate of all picker views. Implement the pickerView:didSelectRow:inComponent: method declared by the UIPickerViewDelegate protocol. That method has an instance of UIPickerView as parameter: that's the one which value was changed. To obtain the row of that picker view, you can send your array the indexOfObject: method.
Create a subclass of a UITableViewCell. That subclass should get a reference to whatever you want to update, and then it can simply create (or IBOutlet link) to the picker and be a delegate of the picker.
So Cell should have:
- (void) passStuff:(NSMutableDictionary *)datamodel key:(NSString *)key values:(NSArray *)values {
_privateWeakRefDataModel = datamodel;
_privateCopyKey = key;
_privateValues = values;
[picker reloadData];
}
#pragma mark - Picker Delegate Code here
This way the cells will handle updating your data model directly. Keeps your code much cleaner.

Duplicating a UITableView with a different data source

I have a UITableView in a ViewController with a custom UITableClass implemented. The table displays different songs that the user can play. The table is populated by a method that pulls data from a server. This method is called in ViewDidLoad.
The user can also tag songs as a 'favorite'. I'd like the user to be able to view all of their 'favorite' tracks in a new `UITableView'. This table should be exactly the same, only with a different data source (only favorited tracks from the server).
How should I implement this? Should I create another method that loads new data to the table with only 'favorited' tracks? Should initialize a new UITableView with the same class and somehow set a different data source or a new ViewController? If so, how?
There will be a slight difference between the two ViewControllers that contain the UITableViews. The original ViewController with all of the tracks will have a button that either changes the datasource or initializes a new UITableView (depending on how it's implemented). The 'favorited' ViewController will have a back button.
I would create a segmented control that has options for "Favorites | All" and when it is switched a BOOL called favoritesOnly or something like that is switched from YES to NO or vice versa. My songs would be kept in an NSArray of NSDictionarys called songsArray and I would use this as my DataSource methods:
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(favoritesOnly)
{
NSInteger count = 0;
for(int n=0; n<[songsArray count]; n++)
if([[[songsArray objectAtIndex:n] objectForKey:#"Favorite"] isEqualToString:#"YES"])
count++;
return count;
}
else
{
return [songsArray count];
}
}
and then for the cells:
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *theCell = [tableView dequeueReusableCellWithIdentifier:#"Proto Cell"];
if(favoritesOnly)
{
NSInteger count = -1;
for(int n=0; n<[songsArray count]; n++)
{
if([[[songsArray objectAtIndex:n] objectForKey:#"Favorite"] isEqualToString:#"YES"])
{
count++;
if(count==[indexPath row])
{
//Configure the Cell using [songsArray objectAtIndex:n]
return theCell;
}
}
}
//If you got here there was an error; Error cell?
return theCell;
}
else
{
//Configure cell using [songsArray objectAtIndex:[indexPath row]]
return theCell;
}
}
This way you are using the same set of Data and the same UITableView, you are just using your control to properly delegate how the DataSource displays the information on the UITableView
Now, if you are using CoreData and and NSFetchedResultsController, this is all much much easier.
You can always go the route of just updating a central playlist UITableView, in which case you would just swap the data in your dataSource (in this case, perhaps NSMutableArray *playlist?) and then call [UITableView reloadData]. In this scheme, you avoid the overhead of having multiple views and the trouble of passing data around.
If you're planning to create additional functionality for your favorited song list, a secondary, customized UIViewController might be in order. In this sense, it can be re-used if you decide to have additional song lists. This would be a good solution if you intend to let them do anything additional that you wouldn't want cluttering your main interface with your list(s) such as editing title, song order, etc.
If these two views would be more or less identical, you can just set up a new UIViewController, either pass the new data via property or load it in your init, and then push it onto the view stack. So long as your app is navigation-based, the back button will appear on its own once you push your secondary UIViewController onto the stack. That isn't functionality you need to add on your own. The perks of this include code-reusability, which is a good skill to have as a UI designer and an engineer.
If you just want a read-only view, you can also look into a UIPopoverController with the data that would dismiss once they click away. This solution is not robust in the least and shouldn't be used if you intend the user to be doing anything more than tapping an entry, or if you expect your datasets to get big.
When planning your UI and flow, just make sure you think of what directions you might take it in the future. As mentioned in another answer, how you store your data makes a difference, as well as how you intend to make calls to your server (button clicks? after a set time?)
how do you store your data from the server? if you use CoreData (or MagicalRecord, which I can recommend) that having a fetched results controller with a different argument would be the only change you need.....
Ah, link to MagicalRecord: MagicalRecord
when you are tagging song as a favorite send one flag as a favorite to the web-service and then call another web service in the favorite view controller and make new table view with the same custom class and view the new source coming from server... and if you are storing in sq-lite or using core data make one column extra as favorite and call it in favorite view controller and load it with different data-source.
I would have a refresh method, and a button that switches between "show all" and "show favorites".
Basically, if the button is clicked, switch to the opposite group of objects, and update the text on the button accordingly. The table will always load an array called "tableDataArray" in my example, and you'll get row counts and such from the length of it.
Like...
-(IBAction)refresh {
if ([faveButton.text isEqualToString:#"Show All"]){
tableDataArray = favoriteArray;
[faveButton setText:#"Show Favorites"];
}
else {
tableDataArray = allSongsArray;
[faveButton setText:#"Show All"];
}
[tableView reloadData];
}
Simplest way to do it would be to have two instances of the same view controller. Each instance will have its own data source, one with all the songs, another with only the favorites.

Save data from 1 page and add that data to a tableView

Hey guys i have 2 views the first has a UITableView. The Second Has a textField and when the user presses a "Save" button on the second page, i want the textFields text to be added to the tableView. Here is the code i'm using
- (IBAction)saveButton:(id)sender {
CheckListPracticeViewController * obj = [[CheckListPracticeViewController alloc]init];
[obj.cells insertObject:textField.text atIndex:0];
[self dismissModalViewControllerAnimated:YES];
NSLog(#"%# "[cells objectAtIndex:0]);
[obj.myTableView reloadData];}
For some reason the data isnt being added to the table View does anybody know whats wrong?? Also the NSLog doesnt Work in this method. Thanks a lot Guys :D
That is because you are creating a new instance of CheckListPracticeViewController and updating it rather than the current one which has presented this view controller modally.
Change the first line to,
CheckListPracticeViewController * obj = (CheckListPracticeViewController *)self.parentViewController;
EDIT
First of all be consistent with your data model. If you are loading an array of dictionaries from the plist and later adding strings into that array then you have a serious problem. I will suggest that you create a dictionary object with name and other stuff and add that to the array. I would say doing [obj.cells insertObject:[NSDictionary dictionaryWithObject:textField.text forKey:#"name"] atIndex:0]; instead of [obj.cells insertObject:textField.text atIndex:0]; will fix this current error but I doubt that will fix your problem.
You are each time the button is pressed you alloc/init a new obj, try adding the new data into your actual container.
It's definitely one of these.
Check if array cells is allocated. Most likely it is not. That is why it is not being added to the tableView. You can add it to the init method so that you initialize the array before adding to the array.
Try NSlogging the contents of the array at various points. This will let you know if its exactly what's going on. NSLog the array in IBAction of Add-method, viewWillAppear
You need to make sure that your array is allocated before adding data to it.
NSLog the content of textField.text before adding it to the array. I am guessing that it is not a property, and it is simply null.
Make sure you had assigned self.myTableView = tableView at the end of your cellForRowAtIndexPath
You are creating another instance of CheckListPracticeViewController. I assume thats where your table is. If you are going back to CheckListPracticeViewController (I assume you do since you use [self dismissModalViewControllerAnimated:YES]) you will have to pass your view controller as a week reference or use NSNotification or use NSUserDefaults to store and retrieve this object in the CheckListPracticeViewController.
EDIT
Pass the CheckListPracticeViewController by weak reference to the view that has UITextField.
example:
in the .h of your UITextField class create a controller reference.
#property(nonatomi,assign)CheckListPracticeViewController *controller;
then when you create your new UITextField controller class pass the reference to its creator throught controller instance.
//in CheckListPracticeViewController.m file
myEdiotr.controller = self;
Later use controller instance to save the text from the UITextField.
- (IBAction)saveButton:(id)sender {
[controller.cells insertObject:textField.text atIndex:0];
[controller.myTableView reloadData];
[self dismissModalViewControllerAnimated:YES];
}

Add data to a table View [duplicate]

Hey guys i have 2 views the first has a UITableView. The Second Has a textField and when the user presses a "Save" button on the second page, i want the textFields text to be added to the tableView. Here is the code i'm using
- (IBAction)saveButton:(id)sender {
CheckListPracticeViewController * obj = [[CheckListPracticeViewController alloc]init];
[obj.cells insertObject:textField.text atIndex:0];
[self dismissModalViewControllerAnimated:YES];
NSLog(#"%# "[cells objectAtIndex:0]);
[obj.myTableView reloadData];}
For some reason the data isnt being added to the table View does anybody know whats wrong?? Also the NSLog doesnt Work in this method. Thanks a lot Guys :D
That is because you are creating a new instance of CheckListPracticeViewController and updating it rather than the current one which has presented this view controller modally.
Change the first line to,
CheckListPracticeViewController * obj = (CheckListPracticeViewController *)self.parentViewController;
EDIT
First of all be consistent with your data model. If you are loading an array of dictionaries from the plist and later adding strings into that array then you have a serious problem. I will suggest that you create a dictionary object with name and other stuff and add that to the array. I would say doing [obj.cells insertObject:[NSDictionary dictionaryWithObject:textField.text forKey:#"name"] atIndex:0]; instead of [obj.cells insertObject:textField.text atIndex:0]; will fix this current error but I doubt that will fix your problem.
You are each time the button is pressed you alloc/init a new obj, try adding the new data into your actual container.
It's definitely one of these.
Check if array cells is allocated. Most likely it is not. That is why it is not being added to the tableView. You can add it to the init method so that you initialize the array before adding to the array.
Try NSlogging the contents of the array at various points. This will let you know if its exactly what's going on. NSLog the array in IBAction of Add-method, viewWillAppear
You need to make sure that your array is allocated before adding data to it.
NSLog the content of textField.text before adding it to the array. I am guessing that it is not a property, and it is simply null.
Make sure you had assigned self.myTableView = tableView at the end of your cellForRowAtIndexPath
You are creating another instance of CheckListPracticeViewController. I assume thats where your table is. If you are going back to CheckListPracticeViewController (I assume you do since you use [self dismissModalViewControllerAnimated:YES]) you will have to pass your view controller as a week reference or use NSNotification or use NSUserDefaults to store and retrieve this object in the CheckListPracticeViewController.
EDIT
Pass the CheckListPracticeViewController by weak reference to the view that has UITextField.
example:
in the .h of your UITextField class create a controller reference.
#property(nonatomi,assign)CheckListPracticeViewController *controller;
then when you create your new UITextField controller class pass the reference to its creator throught controller instance.
//in CheckListPracticeViewController.m file
myEdiotr.controller = self;
Later use controller instance to save the text from the UITextField.
- (IBAction)saveButton:(id)sender {
[controller.cells insertObject:textField.text atIndex:0];
[controller.myTableView reloadData];
[self dismissModalViewControllerAnimated:YES];
}

How To Set Nav Bar Item Title From plist's index row?

My data is sourced in a plist and displayed in a tableview with navigation bar.
I want to load the subview with the cell that was clicked.
I know this would set it correct, but I'm not sure how to implement indexPath in the viewDidLoad method?
self.navigationItem.title = [[self.exerciseArray objectAtIndex:indexPath.row]objectForKey: #"name"];
You have an array of Dictionary With you. Now IndexPath is seen called in TableView delegate methods. I doesn't mean that you can't create one. Create an NSIndexpath obect and assign the indexes parameters and send it to the function which contains the above code( separate the code which sets the title from the Cell for row at index path).
But the problem is as I see, You want to show only a specific set of data in dictionary which is stored in an Array. The real problem is You should know which the index of the Array you want to load. to the title and the tableview. If you can know that then its solved.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSIndexPath_Class/Reference/Reference.html
Regards ,
Jackson Sunny Rodrigues