NSIndexpath.item vs NSIndexpath.row
Okay, nobody has given a good answer here.
Inside NSIndexPath, the indexes are stored in a simple c array called "_indexes" defined as NSUInteger* and the length of the array is stored in "_length" defined as NSUInteger. The accessor "section" is an alias to "_indexes[0]" and both "item" and "row" are aliases to "_indexes[1]". Thus the two are functionally identical.
In terms of programming style – and perhaps the definition chain – you would be better using "row" in the context of tables, and "item" in the context of collections.
Using indexPath vs. indexPath.row in tableView.deselectRowAtIndexPath
Your question and confusion stems from the fact that Apple decided to use somewhat imprecise method name/signature
tableView.deselectRowAtIndexPath(indexPath, animated: false)
The "Row" word in the method signature implies that row is going to be deselected, therefore one would expect a row as a method parameter. But a table view can have more than one section. But, in case it doesn't have more sections, the whole table view is considered one section.
So to deselect a row (a cell really) in table view, we need to tell both which section and which row (even in case of having only one section). And this is bundled together in the indexPath object you pass as a parameter.
So the before-mentioned method might instead have a signature
tableView.deselectCellAtIndexPath(indexPath, animated: false)
which would be more consistent, or another option, albeit a bit less semantically solid (in terms of parameters matching the signature)
tableView.deselectRowInSectionAtIndexPath(indexPath, animated: false)
Now the other case - when you implement the delegate method
tableview:cellForRowAtIndexPath
here again (Apple, Apple...) the signature is not completely precise. They could have chose a more consistent method signature, for example
tableview:cellForIndexPath:
but Apple decided to stress the fact that we are dealing with rows. This is an 8 year old API that was never the most shining work of Apple in UIKit, so it's understandable. I don't have statistical data, but I believe having a single section (the whole tableview is one section) is the dominant approach in apps that use a table view, so you don't deal with the sections explicitly, and work only with the row value inside the delegate method. The row often serves as index to retrieve some model object or other data to be put into cell.
Nevertheless the section value is still there. You can check this anytime, the passed indexPath will show the section value for you when you inspect it.
NSIndexPath does not recognize item, section, or row as properties
Do not use the getter/setter dot syntax, use brackets:
po (int)[index row]
po (int)[index section]
Note that the (int)
is necessary to print the row/section as an integer rather than a hex. Other such useful formatting parameters for LLDB can be found here.
EDIT
The Swift overlay to the Foundation framework provides the IndexPath structure, which bridges to the NSIndexPath class. The IndexPath value type offers the same functionality as the NSIndexPath reference type, and the two can be used interchangeably in Swift code that interacts with Objective-C APIs. This behavior is similar to how Swift bridges standard string, numeric, and collection types to their corresponding Foundation classes.
po index.row
po index.section
work as expected. The comment on p
vs. po
still stands.
It is worth noting that you may use IndexPath
in Swift instead of NSIndexPath, as described in the Apple Documentation.
Why is the row property of NSIndexPath a signed integer?
What happens if you use negative numbers?
It isn't wise to use negative values, if you do, you'll get crazy results
NSIndexPath* path = [NSIndexPath indexPathForRow:-2 inSection:0];
The above results in a section of 0, and a row of 4294967294 (which looks like underflow of an NSUInteger
to me!) Be safe in the knowledge that this only occurs within the UIKit Additions category, and not within NSIndexPath itself. Looking at the concept behind NSIndexPath
, it really doesn't make sense to hold negative values. So why?
(Possible) Reason for why it is so
The core object NSIndexPath
from OS X uses NSUInteger
s for its indices, but the UIKit Addition uses NSInteger
. The category only builds on top of the core object, but the use of NSInteger
over NSUInteger
doesn't provide any extra capabilities.
Why it works this way, I have no idea. My guess (and I stipulate guess), is it was a naive API slipup when first launching iOS. When UITableView
was released in iOS 2, it used NSInteger
s for a variety of things (such as numberOfSections
). Think about it: This conceptually doesn't make sense, you can't have a negative number of sections. Now even in iOS 6, it still uses NSInteger
, so not to break previous application compatibility with table views.
Alongside UITableView
, we have the additions to NSIndexPath
, which are used in conjunction with the table view for accessing it's rows and such. Because they have to work together, they need compatible types (in this case NSInteger
).
To change the type to NSUInteger
across the board would break a lot of things, and for safe API design, everything would need to be renamed so that the NSInteger and NSUInteger counterparts could work safely side by side. Apple probably don't want this hassle (and neither do the developers!), and as such they have kept it to NSInteger
.
How exactly does the NSIndexPath row property work
Your understanding is correct. NSIndexPath encapsulates a section and a row. I think your confusion is that BNRItem *p
is not pointing to all 5 items (it's only pointing to one at a time)... rather, the method tableView:cellForRowAtIndexPath:
is called for each row that is being displayed in the Table View.
There is another method, tableView:numberOfRowsInSection:
which is called. I assume this method is returning the number 5, so tableView:cellForRowAtIndexPath:
is called 5 times... each time the indexPath will have a different row, and thus print a different object.
NSIndexPath and IndexPath in Swift 3.0
There is no reason to cast IndexPath
to NSIndexPath
here.
The Swift 3 overlay type IndexPath
has properties
/// The section of this index path, when used with `UITableView`.
///
/// - precondition: The index path must have exactly two elements.
public var section: Int
/// The row of this index path, when used with `UITableView`.
///
/// - precondition: The index path must have exactly two elements.
public var row: Int
which you can access directly:
cell.facilityImageName = self.facilityArray[indexPath.row].imageName
cell.facilityLabelString = self.facilityArray[indexPath.row].labelText
Apparently the Xcode migrator did not a perfect job.
NSIndexPath in Swift
What I don't understand how NSIndexPath works.
For iOS, you can think of NSIndexPath
as a read-only structure that contains two Int
properties section
and row
if you're working with UITableView
s or section
and item
if you're working with UICollectionView
s.
You create them with the NSIndexPath:forRow:inSection:
factory method:
let indexPath = NSIndexPath(forRow: 1, inSection: 0)
and read them by accessing their properties:
print("row is \(indexPath.row)")
How can I know NSIndexPath has property of row?
Xcode has some nice features to help you understand the code you are looking at. In Xcode, Option-click on row
in the above statement line, and it will tell you what it is. In the pop-up, if you click on NSIndexPath UIKit Additions next to Reference, it will bring up the documentation.
Can somebody explain every part of this line please:
let (courseTitle, courseAuthor) = devCourses[indexPath.row]
devCourses
is an array of tuples containing two values of type String
. You can see this by option-clicking on devCourses
and it shows [(String, String)]
. Had it been an array of array of String
it would have said [[String]]
or [Array<String>]
(which is two ways of saying the same thing).
indexPath.row
is just an Int
indicating the selected row of the tableView
.
devCourses[indexPath.row]
then is the tuple at that index. For example, if the row
were 0
, then the tuple would be ("iOS App Dev with Swift Essential Training","Simon Allardice")
.
Finally, you can initialize two variables simultaneously by declaring them as a tuple and initializing them with a tuple. For example:
let (a, b) = (3, 4)
creates two Int
constants a
and b
and assigns 3
to a
and 4
to b
.
So this statement is retrieving the tuple from the array indicated by the integer indexPath.row
and creating two variables, assigning the first variable courseTitle
the value of the first value in the tuple and assigning the second variable courseAuthor
the value of the second value in the tuple.
Update for Swift 3
NSIndexPath
still exists in Foundation, but when working with indexPaths in Swift 3, a new type IndexPath
is now used. This type is a structure.
You can still create an NSIndexPath
in Swift 3, with the following updated syntax, but you can't change the properties:
var ip = NSIndexPath(row: 0, section: 0)
ip.row = 5 // Cannot assign to property: 'row' is a get-only property
but you should use the new IndexPath
structure instead.
IndexPath
is created with a similar syntax:
var ip2 = IndexPath(row: 0, section: 0)
ip2.row = 5 // this works
You can convert between IndexPath
and NSIndexPath
by casting with as
:
let ip = NSIndexPath(row: 0, section: 0)
let ip2 = ip as IndexPath // convert to IndexPath
let ip3 = ip2 as NSIndexPath // convert back to NSIndexPath
All of the Cocoa and Cocoa Touch API's that use indexPaths have been converted to use IndexPath
in Swift.
getting index on NSIndexPath on UICollectionView
Use (indexpath.section*yourTotalColumn)+indexPath.row
to calculate exact index of array for UICollectionView.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
......................
.......................
//Now calculate index of array (datasource) Note : here column is 2.
NSInteger index = (indexpath.section*2)+indexPath.row
cell.label.text = [textos objectAtIndex:index];
return cell;
}
Related Topics
How to Add iPhone 5 Large Screen Support to iOS Apps in Xcode
Dtassetproviderservice Could Not Start Dtxconnection with Simulator
Differencebetween a Property and a Variable in Swift
Exc_Bad_Access When Building Nspredicate
Uiscreen Mainscreen Bounds Returning Wrong Size
Using Scrollview Programmatically in Swift 3
Launch Apple Mail App from Within My Own App
Can't Assign Multiple Buttons to Uinavigationitem When Using Storyboard with iOS 5
Change the Width of Master in Uisplitviewcontroller
Making a Button Persistent Across All View Controllers
How to Programmatically Enable Guided Access (Kiosk Mode) on an Iphone
Uicollectionview Remove Top Padding
How to Put the Image on the Right Side of the Text in a Uibutton
Saving Image to Documents Directory and Retrieving for Email Attachment
Uitextfield Securetextentry Bullets with a Custom Font
Swift - How Creating Custom Viewforheaderinsection, Using a Xib File