select table row don't work, if element out of view - ios

If the app starts, I need to select table row of the last element, that was used.
The name of the last used element I save in plist.
The code I used is:
id plist = [[PlistHandler alloc] init];// FIXME: Dont work with long list, if the element is out of view.
if ([tableData containsObject:[plist readDataForKey:#"selectedFile"]]) {
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[tableData indexOfObject:[plist readDataForKey:#"selectedFile"]] inSection:0];
[self.fileTable selectRowAtIndexPath:indexPath animated:YES scrollPosition:UITableViewScrollPositionNone];
[self tableView:self.fileTable didSelectRowAtIndexPath:indexPath];
}
The problem I found is: If the row is out of view ( table is big and the element if lower then view), I get some exception: Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary setObject:forKey:]: attempt to insert nil value (key: selectedFile)' Maybe someone know the better way to select a row or to work around.
UPDATE:
I debuged a bit and now I know where the issue happen:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
NSString *cellText = cell.textLabel.text;
id plist = [[PlistHandler alloc] init];
[plist writeDataToKey:#"path" andData:[NSString stringWithFormat:#"%#/%#", documentsDirectory, cellText]];
[plist writeDataToKey:#"selectedFile" andData:cellText];
}
It's on the last line, because the cellText is nil, so maybe the index is wrong.
Bit why it works with the elements, that are in the view.

Cell is probably not initialized, because it has not be used. This is, because it is not on the screen.
The deeper problem is that you try to get data from the UI. The UI is for displaying data, not for storing and retrieving data. Retrieve the data from your model. Your application should know how to do this, because it knows how to set the cell.
https://developer.apple.com/library/mac/documentation/general/conceptual/devpedia-cocoacore/MVC.html

Related

Terminating with uncaught exception of type NSException when deleting row from UITableView

I'm working on an app that will update and add user's coordinate to a UITableView when the user has traveled over a preset distance interval. The coordinates will be automatically added to an NSMutableArray, and I use the array to update the table.
Everything load up and work fine (I can edit the table by moving and re-ordering the rows) but whenever I chose to delete a specific row, the program crash with the error "libc++abi.dylib: terminating with uncaught exception of type NSException".
- (void) tableView:( UITableView *) tableView commitEditingStyle:( UITableViewCellEditingStyle) editingStyle forRowAtIndexPath:( NSIndexPath *) indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSArray *items = [[G5SharedStore sharedStore]allCoords];
G5SharedStore *item = items[indexPath.row];
[[G5SharedStore sharedStore]removeItem:item];
//THIS IS WHERE THE ERROR OCCURS
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
The last line is what causes the error, but I'm new to objective-c, so I'm not sure how to fix this. Any help would be appreciated. Let me know if you need more details.
Thanks in advance.
**Edit:
Ok, I played around with the code this morning and it works. The problem is that the array keeps adding more and more items, but the tableview doesn't, unless I go back out and click "show table" button again to refresh it. So whenever I delete something in the tableview, the table's size is inconsistent with the array's size therefore I get the error. Here's my new problem, I tried to solve the above problem by making the table automatically update its data using:
[tableView reloadData];
The table does update, but it keeps adding blank cells ... with no data in it. Here's where I added the above:
- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#" UITableViewCell"
forIndexPath:indexPath];
NSArray *items = [[G5SharedStore sharedStore] allCoords];
G5SharedStore *item = items[indexPath.row];
cell.textLabel.text = [item description];
[tableView reloadData];
return cell;
}
Since I just started iOS programming 1 month ago, I could be wrong. So please guide me.
Thanks again everyone
I can see two problems:
Firstly this article recommends modifying the table view before the data-model (you are doing it the other way round):
It must do two things:
Send deleteRowsAtIndexPaths:withRowAnimation: or insertRowsAtIndexPaths:withRowAnimation: to the table view to direct
it to adjust its presentation.
Update the corresponding data-model array by either deleting the referenced item from the array or adding an item to the array.
Secondly you don't appear to be calling beginUpdates and endUpdates around that call. To quote the reference:
Note the behavior of this method when it is called in an animation
block defined by the beginUpdates and endUpdates methods.
Instead of delete row delete object from the array and reload table
- (void) tableView:( UITableView *) tableView commitEditingStyle:( UITableViewCellEditingStyle) editingStyle forRowAtIndexPath:( NSIndexPath *) indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSArray *items = [[G5SharedStore sharedStore]allCoords];
G5SharedStore *item = items[indexPath.row];
[[G5SharedStore sharedStore]removeItem:item];
//Remove this
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
//Add This Line
[tableView reloadData];
}
}

NSUserDefaults UITableView

I am a novice programmer. Because i'm a newby at Stackoverflow I cannot comment someones anwser yet. I got a question about this post : How to use NSUserDefaults to save data from ViewController and retrieve it to TableViewController when app reruns
I try to solve the problem and I read many topics on Stackoverflow, but I couldn't find the solution. I have the same code as Rhenzzz and I implemented the solution explained by Jay.
I have an error in cellForRowAtIndexPath method at the line NSString *itemWish = itemDictionary[#"itemWish"];.
Error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[WishListItem objectForKeyedSubscript:]: unrecognized selector sent to instance 0x9dc4d80'
My full method is :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"wishlistCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
NSDictionary *itemDictionary = self.wishlistItem[indexPath.row];
NSString *itemWish = itemDictionary[#"itemWish"];
cell.textLabel.text = itemWish;
return cell;
}
EDIT :
I forget to precise that my error occurs when I add a new item. The tableview displays datas when I launch the App. But when I add data on my ViewController and then save & go back to the Tableview by clicking on my Done button, I have the error describe above.
So I put some NSLog in cellForRowAtIndexPath : NSLog(#"Display the dictionary:%#",itemDictionary ); and NSLog(#"Display the item:%#",itemWish );. Everything is right.
So my problem comes certainly from the IBAction :
- (IBAction)unwindToList:(UIStoryboardSegue *)unwindSegue {
AddItemViewController *source = [unwindSegue sourceViewController];
WishlistItem *item = source.wishItem;
if (item != nil) {
[self.wishlistItem addObject:item];
[self.tableView reloadData];
}
}
If I delete the [self.tableView reloadData]; the error disappears but obviously my Tableview is not auto-updated.
Thanks for your help !
Given the error, it is clear that self.wishlistItem is an array of WishListItem objects and not an array of dictionaries. You should change these two lines:
NSDictionary *itemDictionary = self.wishlistItem[indexPath.row];
NSString *itemWish = itemDictionary[#"itemWish"];
to:
WishListItem *wishListItem = self.wishlistItem[indexPath.row];
NSString *itemWish = wishListItem.somePropertyGivingTheDesiredValue;
where obviously you need to use the appropriate property on wishListItem to get the value you want from it.

How to skip a specific string when populating my UITableView

I am populating a tableview from data that is received from a server. The data is a list of user activities within a given timeframe. One such activity is "Login". I do not wish to populate my tableview with this string but I'm not sure how to skip it when populating my tableview.
Here is how I populate the cell
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{ static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
#try{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if ([action isEqualtoString:#"Login"]) {
return cell;
}
return cell;
}#catch (NSException *ex) {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
return cell;
}
}
As you can see I tried using return cell but as you probably know it gives me a blank cell when the table is displayed. I'm sure there is a simple line of code for this but I came up blank with the search terms I used. Could someone please enlighten me! Thanks!
P.S. you may be thinking I am not putting anything in any of the cells but I pulled out a bunch of code to keep this short.
UPDATE:
Thanks for the heads up on "isEqualtoString:" Everything worked fine with "isEqual" but I changed it given that I received so many suggestions to do so. But this is not what I am asking.
To be more clear if I had an array containing the terms: view, view, login, view. When my tableview was populated I would have 4 cells that said; view, view, login, view. I simply want to ignore the term login so that I would have 3 cells that all said view. Thanks!
There can be many way to do this.
I Belive that UITabelView should display what its datasource (here datasource is self.fetchedResultsController) contains.
What you can do is create another NSArray from self.fetchedResultsController which does not contain this object.
Try this:
NSMutableArray *newSource = [[NSMutableArray alloc] init];
for(int i = 0; i < self.fetchedResultsController.count ; i++)
{
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSString *action = [object valueForKey:#"theActionName"];
if (![action isEqual:#"Login"])
{
[newSource addObject:action];
}
}
[tableView reloadData];
Now use newSource instead of self.fetchedResultsController
You might think that using one more array is not good. But believe it it is far easier than using the same array with condition. You don't have to worry about that condition when you perform some operation with your UITableView like remove object by using indexpath.
try using if ([action isEqualToString:#"Login"])
When you want to compare strings you need to use this isEqualToString .
Change this line
if ([action isEqualToString:#"Login"]) {
return cell;
}
You are using the wrong function to compare your input string and the given data variable.
They both are NSString objects so use :
if([action isEqualToString:#"Login"])
{
//enter your code here
}
#Ben : I am assuming that you have registered you cell through nib as you are using dequeueReusableCellWithIdentifier.
Make your tableview content as "Dynamic prototype" (You can see this in Attributes Inspector of table view) and change your table view cell style as custom (You can see this in Attributes Inspector of tableview cell).

Select Saved Checkmarked Rows on viewdidload

I have a settings page with a long list with checkmark accesories. Users can select as many rows as they want and I have them saving in NSUserDefaults. I want their previous selections to be selected next time they open settings so I've tried this:
NSArray *array = [NSMutableArray arrayWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:#"choices"]];
if (array.count !=0) {
NSLog(#"not empt");
for (id obj in array) {
NSIndexPath *path = [NSIndexPath indexPathWithIndex:obj];
[self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionTop];
}
}
But the app crashes with this error every time:
erminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid index path for use with UITableView. Index paths passed to table view must contain exactly two indices specifying the section and row. Please use the category on NSIndexPath in UITableView.h if possible.
What am I doing wrong? Thanks
The error is quite explanatory. NSIndexPaths in UIKit require two indexes one for the section and one for the row. It's explained here
Assuming you only have one section in your table view:
for (id obj in array) {
NSIndexPath *path = [NSIndexPath indexPathForRow:obj inSection:0];
[self.tableView selectRowAtIndexPath:path animated:NO scrollPosition:UITableViewScrollPositionTop];
}

How to jump to the next row in detailview

i have a TableView which loads a detailview in didSelectRow. I have no problems with the data's.
I am using coreData and to populate the TableView i am using a NSFetchedResultsController.
Now, i want to make a next and previous function in the detailView to jump to the next or previous Table(row) Element. Next Previous like in the Mail-App.
I know that i have to use a button with IBAction.
But how can i make this function?
thanks,
brush51
Edit 1:
I have it done so:
- (IBAction) previousCard:(id) sender {
NSLog(#"previousBtn");
DashboardViewController *parent = (DashboardViewController *)self.parentViewController;
NSIndexPath *actualIndexPath = selectedRow2;
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:actualIndexPath.row-1 inSection:actualIndexPath.section];
NSLog(#"newIndexPath: %#", newIndexPath);
[parent.tableViews selectRowAtIndexPath:newIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle]; //HERE I GET SIGABRT
}
But i get an error:
-[UIViewController tableViews]: unrecognized selector sent to instance 0xd758ae0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController tableViews]: unrecognized selector sent to instance 0xd758ae0'
How to solve this?
With your UITableView, you can get the selected row by:
- (NSIndexPath *)indexPathForSelectedRow
And set the selection by incrementing the indexPath.row:
- (void)selectRowAtIndexPath:(NSIndexPath *)indexPath animated:(BOOL)animated scrollPosition:(UITableViewScrollPosition)scrollPosition
then you action could be:
-(IBAction)nextCell:(id)sender {
NSIndexPath * actualIndexPath = myTableView.indexPathForSelectedRow;
NSIndexPath * newIndexPath = [NSIndexPath indexPathForRow:actualIndexPath.row+1 inSection:actualIndexPath.section];
[myTableView selectRowAtIndexPath:newIndexPath animated:YES scrollPosition:UITableViewScrollPositionMiddle];
}
for that you can manage with your DataSource array.
when you load your detail view at that time you pass your index of array(indexPath.row). by that index you fetch data in detail view. and using increment and decrement in that index you get data for next and previous cell.
Steps
1) setup your tableView.
2) when redirect to DetailView at that time set one int variable for store current indexPath.row . so define one int in detail View.
3) using next and previous button manage indexpath.row which is in int variable.
and represent appropriate data from Source array.
You can use:
(UITableViewCell *)cellForRowAtIndexPath:(NSIndexPath *)indexPath
To get the cell you want (next or previous).
And then set the returned cell "Selected" property to YES.
cell.selected = YES

Resources