nsindexpath access to row to section property causes SIGABRT? - ios

Targeting iOS 5.0 I see SIGABRT when I try to access row or section properties of NSIndexPath object in the following code:
NSIndexPath* path = [[NSIndexPath alloc] initWithIndex:0];
int row = path.row; //SIGABRT
int section = path.section;//SIGABRT
This example suggests using indexPathWithIndex: instead http://developer.apple.com/library/mac/#samplecode/SourceView/Listings/BaseNode_m.html#//apple_ref/doc/uid/DTS10004441-BaseNode_m-DontLinkElementID_6
path = [NSIndexPath indexPathWithIndex:0];
The results remain consistent. Does anyone have an explanation of why this might happen? Is it that we just cannot operate on NSIndexPath in iOS 5.0?
Thanks in advanced.

Try creating the index path using indexPathForRow:inSection:
NSIndexPath* path = [NSIndexPath indexPathForRow:0 inSection:0];

The only thing I can think of is to make sure you have UIKit.framework as one of your frameworks. You can do this by pressing the plus button in the "Link Binary With Libraries" section under "Build Phases" on your target. Also, make sure that you import NSIndexPath.h in the file you're trying to access the index path from.
I've run into this problem before, and this solved it. That's because although NSIndexPath is universal between Cocoa and CocoaTouch, the Cocoa version doesn't have properties row and section.
If you already have UIKit.framework, try using [NSIndexPath indexPathForRow:row inSection:section] instead of [NSIndexPath indexPathWithIndex:index].

I think the problem is that indexPathWithIndex: creates a one-node index path. Same for initWithIndex:. The section and row properties come from the UITableView category to the NSIndexPath class. A one-node index path is invalid for use with a table view because index paths passed to table views must contain two indices specifying the section and row (according to the error message I get when I run your code). The following code creates an index path with two indices and runs without throwing an NSInternalInconsistencyException:
NSUInteger x[] = {0 , 0};
NSIndexPath *path = [[NSIndexPath alloc] initWithIndexes: x length: 2];
int row = [path row];
int section = [path section];
row = path.row;
section = path.section;
Is this what you meant by "operate on NSIndexPath in iOS 5.0"?

Related

Why NSIndexPath length always show 2?

I have created a NSIndexPath object but when I print the value of its length property it will always show the value as 2.
NSIndexPath *index = [NSIndexPath indexPathForItem:0 inSection:4];
{length = 2, path = 4 - 0}
Why length is always 2?
Because the index path is made of two indexes - the section and the item number.
basically NSIndexPath is combination of Section and Row, so it will show length as 2.

How Can I Get The indexpath and row in XCODE 5

I have an app that used to work before I upgraded to XCODE 5. I needed to find the row that was selected for a structure I was displaying which has over 100 rows so obviously can be scrolled on the display. The code that used to work is:
NSIndexPath *indexPath = [self.mainTableView indexPathForCell:myCell];
NSInteger row = [indexPath row];
Now, regardless of the row selected, the value of row is always 0. Anyone have any suggestions for me? Thanks.
This worked for me...
CGPoint pos = [pressedButton convertPoint:CGPointZero toView:self.mainTableView];
NSIndexPath *indexPath = [self.mainTableView indexPathForRowAtPoint:pos];
NSInteger row = [indexPath row];
Remember that in Objective-C, you can always send a message nil, and methods that return something (i.e., not void) will return either nil(for an object) or 0 (for a value) when sent to nil (for structs, it is more complicated; read this).
So make sure that:
self.mainTableView is not nil
indexPath is not nil

Crash with tableView endUpdates using RATreeView

I'm using the RATreeView component at https://github.com/Augustyniak/RATreeView by RafaƂ Augustyniak.
Using the posted /Demo code on github:
Add:
RADataObject *rdo = [self.data objectAtIndex:0];
[self.treeView expandRowForItem:[rdo.children objectAtIndex:0]];
at the bottom of viewWillAppear.
Change the lines of the phone objects to:
(void)loadData
{
RADataObject *phone2 = [RADataObject dataObjectWithName:#"Phone 2" children:nil];
RADataObject *phone3 = [RADataObject dataObjectWithName:#"Phone 3" children:nil];
RADataObject *phone4 = [RADataObject dataObjectWithName:#"Phone 4" children:nil];
RADataObject *phone1 = [RADataObject dataObjectWithName:#"Phone 1" children:[NSArray arrayWithObjects:phone2, phone3, phone4, nil]];
RADataObject *phone = [RADataObject dataObjectWithName:#"Phones"
children:[NSArray arrayWithObjects:phone1, nil]];
(This gives a nested list, where phone -> phone 1 -> phone2, phone3, phone4)
This reproduces the crash that I am having in my app.
It crashes on:
(void)expandCellForTreeNode:(RATreeNode *)treeNode withRowAnimation:(RATreeViewRowAnimation)rowAnimation
with an EXC_BAD_ACCESS for:
[self.tableView endUpdates];
I've traced through this for a couple of days, and am not sure how to work around this crash (or even why it is happening).
The error message I get using your code is the following. To reproduce this error, move
[self.treeView expandRowForItem:[rdo.children objectAtIndex:0]];
to viewDidAppear.
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'Invalid update: invalid
number of rows in section 0. The number of rows contained in an
existing section after the update (24) must be equal to the number of
rows contained in that section before the update (12), plus or minus
the number of rows inserted or deleted from that section (24 inserted,
0 deleted) and plus or minus the number of rows moved into or out of
that section (0 moved in, 0 moved out).'
The number of rows has changed to 24, copying existing rows and insert them to the table, but the insertion is not successful.
It seems the thing you want to do is to expand a sub node, you can do that by looking at the implementation of didSelectRowAtIndexPath delegate method, because expanding a row is just like clicking a row. To do it manually add the following code.
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
RATreeNode *treeNode = [self.treeView treeNodeForIndexPath:indexPath];
[self.treeView expandCellForTreeNode:treeNode];
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:1 inSection:0];
RATreeNode *treeNode1 = [self.treeView treeNodeForIndexPath:indexPath1];
[self.treeView expandCellForTreeNode:treeNode1];
It is just as if you click row 0, and row 1 sequentially. You also need to import this header file.
#import "RATreeView+Private.h"

Move rows to bottom in a TableView which uses CoreData

In my app I have a folder-file (one-to-many relationship).So when I open my app, my firstViewController contains all files and when clicked on each folder, it opens a tableViewController displaying files in that folder.
Now here whenever I swipe any row, it is moved to bottom row and the table is update accordingly, the next swiped row will go and sit above the first swiped row.
Eg, at present if my table contains
0 1 2 3
A B C D
After swiping A
0 1 2 3
B C D **A**
after swiping B
0 1 2 3
C D **B A**
and so on,
To do this functionality, I should update the NSOrderedSet also
which is shown below
for (int i = 0; i < [self.folder.file count]; i++)
{
File *file = [self.folder.file objectAtIndex:i];
if(file.completedStatus == false)
{
m_position = i;
m_finalIndexPath = [NSIndexPath indexPathForRow:i inSection:0];
}
}
file.completedStatus = YES;
id obj = [self.folder. file objectAtIndex:row];
NSMutableOrderedSet *files = [self.folder.file mutableCopy];
[files removeObjectAtIndex:row];
[files insertObject:obj atIndex:m_position];
NSIndexPath *currentIndexPath = [NSIndexPath indexPathForRow:row inSection:0];
[m_tableView moveRowAtIndexPath:currentIndexPath toIndexPath:m_finalIndexPath];
self.folder.file = files;
}
[self.managedObjectContext save:nil];
[m_tableView reloadData];
This works fine in this View, and here self.folder, is particular folder on which the user clicks
Now I have another ViewController called TestViewController where I have some of the file objects irrespective of in which ever folder they are present . I have populated the table of this TestViewController with these files, Now here also, when I swipe the cells, they will change the color but not move their position as above
Eg
0 1 2 3
A C B D
after swiping A and B
0 1 2 3
**A** C **B** D
Now here A can belong to folder 1 and B can belong to folder 2,
when I close(dismiss) this TestViewController, What should happen is that
a) it shows me the fileViewController by default
b) the color of file A should change and it should move to a position by checking whether there are any swiped cells already. If yes, it should be placed above it or else at the bottom.
c) similarly for color B.
Regards
Ranjit.
Ranjit,
About your question I cannot understand what you are asking here. So, please provide some other details.
To know the folder a specific file belongs to, this is quite simple to achieve.
If you have set up an inverse relationship between a file and a folder, simply access that relationship.
For example, if the inverse relationship is called toFolder, you can retrieve the current folder like
Folder* currentFolder = currentFile.toFolder; // or access it through KVC
To create an inverse relationship take a look here: Core data structure use multiple entities or not?

How to change uitableviewcell data in different section?

I want to change the data of two rows in two different sections when one of them is selected so that they will have the same answer. But it is not working:
NSIndexPath *indexPath1 = [NSIndexPath indexPathForRow:row1 inSection:section1];
cell = [self.tableView cellForRowAtIndexPath:indexPath1];
//DO SOMETHING WITH CELL LABEL
NSIndexPath *indexPath2 = [NSIndexPath indexPathForRow:row2 inSection:section2];
cell = [self.tableView cellForRowAtIndexPath:indexPath2];
//MAKE THIS CELL LABEL SAME AS THE LAST ONE
It doesn't work if the second cell is in a different section! Any suggestion?
You will get a nil from cellForRowAtIndexPath: if one of the cells isn't visible at the moment.
You should therefore get the needed entry from your data-model, not from the UI.
Change the needed information there:
NSArray *section1Data = [self.dataModell objectAtIndex:section1];
NSDictionary *dataObject1 = [section1Data objectAtIndex:row1];
[dataObject1 setValue:#"My new Text." forKey:#"theTextPropertyKey"];
NSArray *section2Data = [self.dataModell objectAtIndex:section2];
NSDictionary *dataObject2 = [section1Data objectAtIndex:row2];
[dataObject2 setValue:#"My new Text." forKey:#"theTextPropertyKey"];
Then reload the needed cells in the UI:
NSArray *indexPaths = #[indexPath1, indexPath2];
[self.tableView reloadRowsAtIndexPaths:indexPaths];

Resources