Nsindexpath.Item VS Nsindexpath.Row

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:

  1. po (int)[index row]
  2. 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.

  1. po index.row
  2. 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 NSUIntegers 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 NSIntegers 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 UITableViews or section and item if you're working with UICollectionViews.

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



Leave a reply



Submit