numberOfRowsInSection and prepareForSegue method problems - ios

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

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;
}

How do you pass the object selected in tableView:didSelectRowAtIndexPath to new UIViewControllers pushed onto the stack?

I'm displaying a list of items in a tableViewController, then when a row is selected pushing a viewController with a .xib file onto the stack, giving a more detailed explanation of the item in a textView with a few UIButtons to select for further action. All of this works so far.
The problem I'm running into is pushing yet another viewController onto the stack with editable textViews containing information from the original object selected in the tableView. I can get the viewController and .xib to load, but not the data.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
JASDetailViewController *dvc = [[JASDetailViewController alloc]init];
NSArray *ideas = [[JASIdeaStore sharedStore]allIdeas];
JASIdea *selectedIdea = ideas[indexPath.row];
dvc.idea = selectedIdea;
[self.navigationController pushViewController:dvc animated:YES];
}
This populates the DetailViewController perfectly. Then, when moving to the next viewController:
- (IBAction)editButton:(id)sender
{
JASEditViewController *evc = [[JASEditViewController alloc]init];
//NSIndexPath *path = (NSIndexPath *)sender;
//NSIndexPath *path = [[NSIndexPath alloc]init];
//path = [NSIndexPath indexPathForItem:0 inSection:0];
NSArray *ideas = [[JASIdeaStore sharedStore]allIdeas];
JASIdea *selectedIdea = // Looking for a solution here. . .
evc.idea = selectedIdea;
[self.navigationController pushViewController:evc animated:YES];
}
I can get the EditViewController to load, but not the data. The gaps and commented out sections represent some of my attempts to get this to work. By specifying a particular indexPath, I can make an idea show up, but have been unable to get my original selection from the tableView to pass through.
Don't you want this?
JASIdea *selectedIdea = self.idea;
If I understand your code correctly, you're going from an edit button on JASDetailViewController to JASEditViewController, but the JASIdea instance is staying the same. You passed selectedIdea from your table view's didSelectRowAtIndexPath into JASDetailViewController.idea. That means that it's there in self.idea when you're inside JASDetailViewController.editButton
Since you're getting your data from a shared instance, there's no need to pass selectedIdea to JASDetailViewController. Instead, you should create a property, lets call it selectedIndex, and pass that. That way, you'll have that value to pass on to JASEditViewController as well.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
JASDetailViewController *dvc = [[JASDetailViewController alloc]init];
dvc.selectedIndex = indexPath.row;
[self.navigationController pushViewController:dvc animated:YES];
}
In viewDidLoad of JASDetailViewController, you can get the selected idea with,
JASIdea *selectedIdea = ideas[self.selectedIndex];

Values are not displaying in table view in ios

I have declared an array in ViewController and displaying it in table view. I am passing values for an array from EditViewController. But the values are not displaying in table view. I am using following code.
ViewController.h
#property (nonatomic, strong) NSMutableArray *tableData;
ViewController.m
ViewDidLoad:
tableData = [NSMutableArray arrayWithObjects:#"",nil];
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
cell.textLabel.text = [tableData objectAtIndex:indexPath.row];
return cell;
}
EditViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
ViewController *vc;
vc = [segue destinationViewController];
NSString *str = [NSString stringWithFormat:#"%ld", selectedRow];
[vc.tableData addObject:str];
}
Please advice.
Connect the delegate and datasource to self in the viewDidLOad of editViewController
tableView.delegete=self;
tableView.Datasource=self;
If there is no data in the tableview itself, hit a breakpoint at
cellForRowAtIndexPath,
and Still if it dsnt hits the breakpoint,connect the Delegate and Data source for the tableview with the View Controller.
[EDIT]
If it is still not called, go to storyboard, check if the bounds of the tableview, is more than that of the vc, that means, check if the tableview is inside the view controller and no part of the tableview is crossing the bounds of the view controller.
Plz make sure you have
-tableView:numberOfRowsInSection:
method defined. This method should return value greater than 0 so that
-tableView:cellForRowAtIndexPath:
gets called.
you are add string to nsarray object which is not allocated.
you have to create nssarray with string and pass to the vc.tableData.
There may be a few problems with this.
First, it's best to set a the NSMutableArray property "tableData" to an existing array passed in during the segue. Right now you're adding a single string to a mutable array which, unless you wrote a custom initializer for the ViewController in which you alloc-init'ed the NSMutableArray, it can't exist until ViewDidLoad which is after the segue is performed, so you're passing the string to black abyss of "nil".
It's best to use base types as receiving properties in prepareForSegue, and then in your case to pass the ViewController's array an already existing array from the EditViewController.
Also, you may not be telling the view controller how many cells to actually create. Make sure numberOfSectionsInTableView returns a value (in this case just 1), and that numberOfRowsInSection returns "[self.tableData count]".
And if you didn't create ViewController as inheriting from UITableViewController, you'll need to set that, and connect the delegate and datasource manually in the storyboard like Light Yagami pointed out. Though it would probably be easier to just create a new custom class file that inherits from UITableViewController because it will give you some good boilerplate code.
And also make sure that in your storyboard, your TableViewController's class is set to your custom class file.
I hope you did not pass numberOfSectionsInTableView as 0. Please check that once. It must be 1 or more based on requirement. And same for numberOfRowsInSection.
Remove this line from your ViewDidLoad Method
tableData = [NSMutableArray arrayWithObjects:#"",nil];

UICollectionView - pass array date via segue for selected indexpath

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.

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