UICollectionView - pass array date via segue for selected indexpath - ios

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.

Related

Passing NSDictionary to another controller using UITableView

I have this NSDictionary:
{
Name =
(
"Lucas",
"Tom"
);
Surname =
(
"Jhon",
"Smith"
"Hop"
);
Name is a simple NSArray and Surname is a NSMutableArray.
Ok now my problem is this:
Starting from this dictionary, I must show in UITableView the key of each element of the NSDictionary. For example, in this case, UITableView will have two items, one call Name and the other Surname.
When I click on an element of the UITableView I will have to go to another controller that will show me all the data of the clicked cell. If for example, I click on Surname, when I open the new controller, I'll have to get it like Jhon, Smith and Hop.
To get started, I tried to show the UITableView before all the keys by writing:
self.KeyArray = [myDictionary allKeys];
and in the cellForRowAtIndexPath method:
cell.textLabel.text = [self.KeyArray objectAtIndex: indexPath.row];
But this is a wrong approach, because I'm going to lose all the information related to that specific key. Do you have any idea how I can do it?
You can use delegate to send that NSMutableArray to another controller.
Lets say your first view controller is "A" which has those name and surname keys. And second Controller is "B" which will has the array that you want to send.
Now,
1. Create a protocol in A controller.
2. Create the delegate object of that protocol.
3. Create 1 Method in A controller which can have a parameter Like :- (NSMutableArray *).
4. Implement that protocol in to B Controller.
5. Declare the method in Controller B that you defined in Controller A
6. Call that method with the help of delegate object in didSelectRowAtIndexPath and Pass that Object in that method.
7. Now you have the NSMutableArray in that method and you are free to use that values.
You can do like that in didSelectRowAtIndexPath write below code
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *keyOfMainDic = [self.KeyArray objectAtIndex:indexPath.row]; // in the keyOfMainDic, you will get selected key name of your main dictionary
NSMutableArray *temArray = [yourMaindict objectForKey:keyOfMainDic] // You will get array of specific key.
// Here you just need to pass "temArray" to your destination controller.
}
First you should define a segue from your view controller that has tableview to your detail controller and give it an identifier in storyboard.
Then define a property into your detail controller header inherit from KeyArray type.
After that, just code it like below. This is just suggestion, please use a model for your array instead of dictionary.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
self.KeyArrayItem = [self.KeyArray objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:#"yourSegueID" sender:self.KeyArrayItem];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
AnotherController *controller = segue.destinationViewController;
controller.KeyArrayItem = sender;
}

numberOfRowsInSection and prepareForSegue method problems

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

Passing data from custom table cell to text fields

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;

IOS - UICollectionView

I have the following code which works out which section/data index to pass to a destination controller based on the clicked cell.
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
self.selectedItIndex = indexPath.row; // define NSInteger selectedItemIndex property in your interface
self.selectedSection = indexPath.section;
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if ([segue.identifier isEqualToString:#"sightSeg"]) {
NSString *s = self.sectionData[_selectedSection];
NSPredicate *pred = [NSPredicate predicateWithFormat:#"siteSection like %#", s];
NSArray *filteredArr = [self.sightsArray filteredArrayUsingPredicate:pred];
NSLog(#"Value of hello = %#", filteredArr);
sightsObject *rightS = filteredArr[_selectedItIndex];
_finNo = _selectedItIndex +=1;
NSLog(#"balls = %#",rightS );
SightViewController *destController = (SightViewController *)segue.destinationViewController;
destController.viewTit = rightS.siteTitle;
}
}
The code works fine first try (as in the correct data is passed relevant to the cell/section clicked) - the issue I have is that if you return to the parent controller and select another cell - the same information is passed again - if you repeat the process selecting a 3rd cell - the data for the second cell clicked is passed - so its as though its a step out of sync!?
Can anyone offer any advice? - Is there a way to only run the sgue code once the values have been set in the didselectpath method?
The sender parameter in prepareForSegue will be the collection view cell you've tapped. Use the following code to derive your index at the point of sending:
NSIndexPath *selectedIndexPath = [self.collectionView indexPathForCell:sender];
You don't need the code in didSelectItem...
Try calling [collectionView indexPathsForSelectedItems] inside prepareForSegue: to get the index path instead of saving it off in collectionView:didSelectItemAtIndexPath:

How to pass the in-place edited content back to the previous tableview controller (update the model)

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.

Resources