I am creating a demo app of an Address Book, which saves people info in an array and displays it in a custom table cell.
The first controller saves the info entered by the user in text fields in an array.
The second controller displays the info in a custom table cell.
The third controller is the same as the first with the only difference is that it will be used not for storing data, but to update the data.
What I now want is to update the table cell data. I have created an update button, on click I am segueing to the 3rd controller.
What I want is the information displayed in a particular cell, to be passed to the 3rd view controller text fields, when the update button is clicked.
How can I achieve this?
I think you store your data in some array or something similar structure. So you can get data from it like this
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)newIndexPath {
MyThirdViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:#"ThirdViewController"];
vc.dataToDisplay = self.myDataArray[indexPath.row];
}
Then in your third view controller you will have data you need to display.
For example if you know order of data in your new array, you can fill your text fields like this
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//if your data is an array
self.firstTextField.text = self.dataToDisplay[0];
self.secondTextField.text = self.dataToDisplay[1];
//and so on
//if your data is a dictionary
self.firstTextField.text = self.dataToDisplay[#"name"]; //for string objects
self.secondTextField.text = [self.dataToDisplay[#"age"] integerValue]; //for integer values
}
//in your third viewcontroller.h
#property NSString * textfieldname;
#property NSString * textfieldage;
//in your second viewcontroller.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"identifiername"]){
NSIndexPath *ip = [yourtablename indexPathForSelectedRow];
thirdviewcontrollerr *targetVC = [segue destinationViewController];
targetVC.textfieldname=[[arrayname objectatindex:ip.row]valueforkey:name];
targetVC.textfieldage=[[arrayname objectatindex:ip.row]valueforkey:age];
//in your thirdviewcontroller.m
nametextfield.text=_textfieldname;
agetextfield.text=_textfieldage;
Related
I am new to iOS development and I am having a trouble with counting objects from Array which contains Dictionaries.
My data structure looks like this and it's located in another custom class:
Library header file
Library implementation file
There will be quite a lot of them (now only 4 just for testing) and I need to count NSStrings with key kEviela.
I need this counting to calculate number of rows required for my tableView:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return ?;
Also I have a detailView where I need to show each of this String separately. So how can I do this in prepareForSegue method?
It's just
return _library.count;
which is the number of dictionaries in the array.
Anyway I recommend to map the dictionary to a custom class.
To get an array of all values for key kEviela write
NSArray *kEvielaArray = [_library valueForKey: kEviela];
This is one of the rare cases where valueForKeyis intended as a KVC method.
First of all,i think you can show number of rows by counting your dictionary objects. I use NSMutableArray converting from dictionary because it's easier for me to manipulate.It's totally personal though.
Also I have a detailView where I need to show each of this String separately.
What you can do?
There is function called didSelectRowAtIndexPath delegate method.
When you select row this function is called.In this function you grab your detailView controller and keep value to one of it's variable(NSString or Something) according to your data.
you can call segue programmatically from here after assigning value.
As an example:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
DetailViewController *detailVC = [[DetailView alloc] initWithNibName:#"DetailView" bundle:nil];
detailVC.userName = [userList objectAtIndex:indexPath.row];
[self.navigationController pushViewController:detailVC animated:YES];
}
or, If you don't want to use like this, then in prepareForSegue method (what you called)
grab your destination view controller and assign value just like previous. That's it.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
vc.dictionary = [youdictionary mutableCopy];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return _library.count;
}
Above is the Way you get the count of array check it out.
Here first you have Array and then you can find out the dictionary value.
NSString *kEvielaValue = [_library valueForKey: "kEviela"];
Try this [[_library valueForKey: kEviela]count];
[_library valueForKey: kEviela] will pick up an NSArray that contains all the values of kEviela and the count message will give you the number of those elements from the main array of _library
I have used a collectionview to present some data - all is fine but I'm struggling with passing the data to a child view by a segue - basically I need to pass the array data for the index path clicked - this is what I have at the mo -
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([[segue identifier] isEqualToString:#"sightSeg"]) {
NSArray *thisarr = [_sightsColView indexPathsForSelectedItems];
SightViewController *destController = [segue destinationViewController];
destController.viewTit = thisarr.siteTitle;
}
}
I currently get an error stating 'property not found on type nsarray'.
cheers
You are calling a property "siteTitle" of an object of type NSArray that is not natively provided by iOS, since it is your custom property not a native NSArray property.
Supposing that your array contains a dictionary for each element into the array, you could do something like this:
// Implement the collection view delegate method
- (void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
self.selectedItemIndex = indexPath.row; // define NSInteger selectedItemIndex property in your interface
}
// then in your prepareForSegue
...
..
.
NSDictionary* selectedItem = (NSDictionary*)[yourDatasource objectAtIndex:self.selectedItemIndex ];
SightViewController *destController = [segue destinationViewController];
destController.viewTit = [selectedItem objectForKey:#"siteTitle"];
// Otherwise if it is a simple nsarray contains strings only
// ( so each element in the array is directly the title of a different view ) you could simply:
NSString* selectedTitle = (NSString*)[yourDatasource objectAtIndex:self.selectedItemIndex ];
SightViewController *destController = [segue destinationViewController];
destController.viewTit = selectedTitle ;
Hope it helps
I guess you data source object for the selected collection cell implements a siteTitle property? However, thisarr contains objects of the class NSIndexPath, i.e. just a "pointer" where to find the object for the selected cell you are interested in. Use the index path(s) to get the approriate object(s) from your actual data source.
Collection views support multiple selection. For that reason, the indexPathsForSelectedItems method returns an array of NSIndexPath objects, one for each selected item.
As Luca Iaco suggests in his post, you can set up your code to respond do the didSelectRowAtIndexPath message, and record the row of the item the user selected.
Based on what you're trying to do, you likely only want single selection. You should set the allowsMultipleSelection flag to false on your collection view in that case.
You can ask the collection view for the current selection using indexPathsForSelectedItems, then fetch the first item in the array:
NSArray *selectedItems = [self.collectionView indexPathsForSelectedItems;
NSIndexPath *selectedItem = selectedItems[0];
int selectedIndex = selectedItem.row;
MyClass *item = (MyClass *) thisarr[selectedIndex];
NSString title = item.siteTitle;
Where you would replace "MyClass" above with the class of your object that is in the thisArr array and has a "siteTitle" property.
I have two table views, one called mainTableViewController (mtvc), the other called detailTableViewController (dtvc). It's very typical click the accessory button on the main tableview cell bring you to the detail tableview kinda thing.
In the prepareForSegue method, the data passed from the main tableview to detail tableview is a NSMutableArray called item.
And this is how I got it displayed: cell.detailTextLabel.text = self.item[indexPath.row];
The cool thing is I managed to do in-place editing on the detail table view cell (overwrote the NSTableViewCell, added a UITextField as subview to each cell).
everything works, the last thing I spent whole day cannot figure out is how do I update the NSMutableArray item after in-place editing taken place, the ultimate goal is in-place editing, and the main tableview data shall reflect the change.
I tried to use delegation and protocol but it does not work (the in-place edited content didn't got passed back, part of the reason is I don't know how to capture the edited content, it's not like it's a text field with a name, I can't just do updatedContent = self.myTextField.text to grab the change)
I'm running out of ideas, any help would be highly appreciated, thanks.
Here's the prepareForSegue in the main tableview controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"toInventoryDetail"]) {
NSMutableArray *selectedItem = nil;
if (self.searchDisplayController.active) {
selectedItem = _searchResults[[sender row]];
} else {
selectedItem = _appDelegate.items[[sender row]];
}
UPFInventoryDetailTableViewController *idtvc = segue.destinationViewController;
idtvc.item = selectedItem;
}
}
and here's the cellForRowAtIndex at the detail tableview controller
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UPFEditableUITableViewCell *cell = [[UPFEditableUITableViewCell alloc] initWithStyle:UITableViewCellStyleValue2 reuseIdentifier:CellIdentifier];
cell.textLabel.text = _appDelegate.title[indexPath.row];
cell.detailTextLabel.text = self.item[indexPath.row];
[cell showEditingField:YES];
return cell;
}
I wrote the delegation but delete them after cause they didn't work.
I had an idea, still using delegation and protocol obviously: when the 'done' button in the detail tableview hit, I go grab all the row contents and build a new array, using delegation to pass this new array back to the main tableview controller, add this new array into the model meanwhile delete the old one. The tricky thing is still HOW CAN I GRAB ALL THE CONTENTS in the detail tableview?
update:
Haha! I think solved half of the puzzle !
here's the solution for the detail tableview controller
- (IBAction)doneUpdate:(UIBarButtonItem *)sender {
[self.delegate addItem:[self newItem]];
}
- (NSMutableArray *)saveItem
{
NSMutableArray *newItem = [[NSMutableArray alloc] init];
NSArray *indexPathes = [self.tableView indexPathsForVisibleRows];
for (NSIndexPath *indexPath in indexPathes) {
UPFEditableUITableViewCell *cell = (UPFEditableUITableViewCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[newItem addObject:cell.editField.text];
}
return newItem;
}
and here's the main tableview controller
- (void)addItem:(NSArray *)item
{
//take the updated item then insert the items array as new item
[_appDelegate.items addObject:item];
//remove the selected item (the one being updated) from the items array
[_appDelegate.items removeObject:_appDelegate.selectedItem];
[self.tableView reloadData];
[self.navigationController popViewControllerAnimated:YES];
}
When you creating a cell - give tags to your UITextFields
You can collect data entered by its delegate methods - you can either make NSDictionary/ key value pairs or you can add it to NSArray.
- (void)textFieldDidEndEditing:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
OR
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if(textField.tag == 11) {
// you can add it to your desired array/dictionary
}
}
You can use Delegation/Protocol or store this values in NSUserDefault and get it back on mainViewController.
Do you have a separate data model class(classes) for your selectedItem? That would be the appropriate way to persist data between the two TableViewControllers. It can be Core Data or simply a NSMutableArray that lives in memory. The DetailViewController updates the item and saves the changes, then the mainTableViewController reloads the TableView (or even just the data backing the previously edited cell.
Perhaps even consider the Model-View-Controller-Store pattern promoted by BigNerdRanch.
I have two ViewControllers conected by a segue, the first is Sub View and the second is Sub Tabela
I want to pass a value from the selected row in that table from my first view controller to my second view controller, so i can define his title.
Here is the code.
SubView.m (My first ViewController)
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// _vinhoArray is the array that I populate the TableView
NSString *selectedRow = [_vinhoArray objectAtIndex:indexPath.row];
// Sub Tabela is the name of Second View
SubTabela *subTabela = [[SubTabela alloc] init];
// tituloTabela is a NSString in my Second View
subTabela.tituloTabela = linhaSelecionada;
// Here i get the Right value
NSLog(#"value %#", subTabela.tituloTabela);
}
SubTabela.h (My second ViewController)
#property (nonatomic, strong) NSString *tituloTabela;
SubTabela.m
#synthesize tituloTabela;
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = tituloTabela;
// Here i get the a Null value
NSLog(#"value %#", tituloTabela);
}
Please Help!
I don't think your passing your data in correctly, it looks as though you are creating an object inside your didSelectRowAtIndexPath and passing the data into that, then discarding this object. What you need to do is call this:
[self performSegueWithIdentifier:<#(NSString *)#> sender:self];
to change the screen and then pass the data like this is the prepareForSegue callback
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SubTabela *vc = (SubTabela *)segue.destinationViewController;
vc.tituloTabela = linhaSelecionada;
}
my code snippet //
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// [tableView deselectRowAtIndexPath:indexPath animated:YES];
if(indexPath.section == 0)
{
if(indexPath.row == 1)
{
WebServiceHandler *handler = [[WebServiceHandler alloc]init];
handler.requestType = eSuburb;
NSMutableURLRequest *searchDetailsRequest = [Service parseGetSuburb:nil];
NSLog(#"user details request of str== %#",searchDetailsRequest);
[handler placeWebserviceRequestWithString:searchDetailsRequest Target:self Selector:#selector(getListOfSuburb:)];
}
after response it jumps into another class with list of all it is data,among all those data I want to populate with it one which user selects
Not sure how you are doing this, but here is how if you are using segues. In this example, each of my table cells contained their relative information in an NSMutableDictionary. The receiving view controller had a NSMutableDictionary property to receive all of the sent data. The last two lines create a ViewController object and has its Dictionary property equal the Dictionary being sent from the selected cell in the table view.
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
NSString *identifier = segue.identifier;
if ([identifier isEqualToString:#"SegueName"]) {
// first get data
NSIndexPath *selectedIndexPath = self.tableView.indexPathForSelectedRow;
NSMutableDictionary *cellData = self.aDictionary[selectedIndexPath.row];
ViewController *nextViewController = segue.destinationViewController;
nextViewController.aDictionary = cellData;
}
}
I would Suggest against using the callback method here. That is not the right way to carry this out.
According to my understanding, what you want to do is once the user selects a row, you wish to pass the selected row's data back to the viewcontroller(lets assume 'vcA') which called the one with the tableview('vcB')...
If this is so you should create a protocol and hence use a delegate to notify the viewcontroller 'vcA' about the selection event and hence pass the required data just as #inertiatic suggested.