How to change default indexPath 0 to 1 of tableView in swift3? - ios

I want to display my data in tableView but I want to start indexPath from 1. But I am not getting any solution .Is there any way I can start indexPath from 1
output I am getting is:
myData 1,2,3,4,5 and indexPath is 0,1,2,3,4
what I want :
myData 1,2,3,4,5 and indexPath is 1,2,3,4,5
because of indexPath start from 0 my data at index 1 get assigned to 0 and so on.
CAN WE INCREMENT indexPath.row by one before loop starts

You can't change indexPath but you can display data as below func
let lblTitle: UILabel? = (cell?.viewWithTag(102) as? UILabel)
lblTitle?.text = "\(indexPath.row + 1)" // here you need to add 1

IndexPath uses arrays which start at index 0.
Each index in an index path represents the index into an array of children

Thank you for your response but I get the solution for this
Here is the solution:
mainArrayRoll.insert("0", at: 0)
I have added an default value to my array so every time indexPath start from zero it deals with my default value and I get my proper output from index location 1.

Related

Convert the original tableview to collectionview data cannot be passed

I want to replace the original tableview with collectionview, the code of the original tableview:
let selectedRow = MarketView.indexPathForSelectedRow!.row
I'm learning online to change to this code and I get an error:
let selectedRow = MarketView.indexPathsForSelectedItems!.first
The error shows:
Cannot convert value of type 'IndexPath?' to expected argument type 'Int'
This is the complete code as shown in the figure
I just learned to use collectionview, how should I modify it, thank you for your help
Unlike indexPathForSelectedRow which returns a single index path indexPathsForSelectedItems returns an array of index paths
And row is not first, the collection view equivalent of row – as the name of the API implies – is item, you have to write indexPathsForSelectedItems!.first!.item.
But it's not recommended to force unwrap the objects. A safer way is
guard let selectedRow = MarketView.indexPathsForSelectedItems?.first?.item else { return }

Int vs. IndexPath Troubles

I am writing a function to loop through all of the cells in a UITableViewController. Here is what I have so far:
var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
i += 1
let cell = tableView.cellForRow(at: i-1)
}
Everything loops correctly until I try to get the cell. It expects an input of type IndexPath, however I am passing in an Int. Whenever I force it as an IndexPath like so:
let cell = tableView.cellForRow(at: i-1 as! IndexPath)
I get a warning saying that it will always fail/ always return nil. Is there a better way to do this, or am I just missing a crucial step. Any help is greatly appreciated. Thanks in advance!
EDIT (A LITTLE MORE EXPLANATION): All the cells are custom classed cells, with a specific variable. I want to loop through all of the cells and get that value.
let visibleCells = tableView.visibleCells
for aCell in visibleCells {
print(aCell.question?.text) <------- this is the value I want
}
Most of the information below has been said by others in the other answers and comments, but I wanted to put it all in one place:
We need to step back from the specifics of the question and ask what you are actually trying to do.
The UITableView method cellForRow(at:) will only return cells that are actually on-screen. If there is only room for 5 cells and you have to scroll to expose the rest, that method will return nil for all but the cells that are visible.
As others have suggested, if your goal is to loop through the cells that are on-screen the property tableView.visibleCells would be a better choice.
If your goal is to loop through all cells that exist in your data then you need to explain what you are trying to do.
As for your specific question, the cellForRow(at:) wants a parameter of type IndexPath. You can't simply cast an Int to IndexPath. That will fail. Instead, as #TaylorM said in their answer, you need to create an IndexPath. If your table view only has a single section then you can simply use
let indexPath = IndexPath(row: i, section: 0)
(Assuming you fix your loop code so your indexes start at 0.)
It also does not make sense to use a while loop like that.
Instead of all of this, I suggest using:
let visibleCells = tableView.visibleCells
for aCell in visibleCells {
//Do something with the cell
}
You should create an IndexPath via code, like this:
let ndx = IndexPath(row:i, section: 0)
Or, to modify your code:
var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
i += 1
let ndx = IndexPath(row:i-1, section: 0)
let cell = tableView.cellForRow(at:ndx)
}
Based on the later edit where you mention that you want the value of a text string on each row, I would suggest that the above is probably not the best way to approach this :) (I know others have already said this, but I didn't want to make assumptions about what you wanted to do unless you specifically stated what you wanted ...)
You are probably better off taking the same approach you take to populate the data for the table view cells via cellForRowAt: to get the question text than to loop through all the table rows, which would result in some issues for non-visible rows as others have indicated already.
If you have any issues with getting the data provided for cellForRowAt:, do share the code for the cellForRowAt: with us and I'm sure one of us can help you figure things out :)
Try
let indexPath = IndexPath(row: i, section: 0)
You may need to adjust the section to fit your needs.
Check out the documentation for IndexPath. Like most classes and structures, IndexPath has initializers. If you need to create a new instance of any object, you'll most like use an initializer.
*also see the comment from #rmaddy:
"Unrelated to your question but I can almost guarantee that your attempt to loop through all of the cells is the wrong thing to do. What is your actual goal with that loop?"
I believe I have figured it out using all of the help from you wonderful people.
In my case, I have a custom class with a variable that I want access to. I can do what Taylor M, Fahim, and Duncan C said: let indexPath = IndexPath(row: i, section: 0)
Then I can add as! NumberTableViewCell to the end, which allows me access to the values defined there. In the end, it looked like this:
var i = 0
while (i < tableView.numberOfRows(inSection: 0)) {
i += 1
var cell = tableView.cellForRow(at: IndexPath(row: i-1, section: 0)) as! NumberTableViewCell
print(cell.question.text!)
}
Thank you all for your help!

Displaying data in a tableView from a filtered array

I have written code that filters events from Core Data and only prints the events that have a date attribute that is equal to a date that was selected in a Calendar. Heres the code:
let predicate = NSPredicate(format: "eventPastStringDate = %#", formatter.stringFromDate(selectedDate))
//This prints the exact data that I want
print((eventsPast as NSArray).filteredArrayUsingPredicate(predicate))
This works and it filters that data how I would like and it prints only the events that I want. The problem is that I do not know how to display this data in the tableView. Usually I can display all the data from Core Data in the tableView like this in cellForRowAtIndexPath...
let ePast = eventsPast[indexPath.row]
let cellPast = self.tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! CustomCell
// Sets labels in cell to whatever user typed in on the events page
cellPast.titlePrototypeCell!.text = ePast.eventPastTitle!
cellPast.datePrototypeCell!.text = "Date: " + ePast.eventPastDateLabel!
return cellPast
...but I am not sure how to access the new data as an array like I did above. Any ideas?
You are going to have a second array in your class. When there is no filter, the two arrays are identical. When there is a filter, then you have a master array with absolutely everything and the filtered array is a small subset.
(class var) myFilteredArray = (eventsPast as NSArray).filteredArrayUsingPredicate(predicate)
Then in your tableview methods:
let ePast = myFilteredArray[indexPath.row]
And make sure to set the table row size to your filtered array count, not the master array count. Otherwise you are going to get out of bounds crashes.

How can I access an item from an array dynamically with Swift

I've got an Array that I'm using to populating the rows of a UITableView.
After a row is selected I need to retrieve information from the Array based on the row selected to populate some outlets (labels, textfields, etc.)
For example:
I create an itemSelected variable in the didSelectRowAtIndexPath in my ViewController for the TableView which I set to indexPath.row
itemSelected = indexPath.row
Then in my viewDidLoad for my otherViewController I need to retrieve the info by
array[itemSelected]
But, I get a compiler error that says: "Expression resolves to unused i-value"
In here you simply accessing the array but not calling any value. As a example if you have a key call "Name" in your array and you want to set it to a UILabel just do it as this.
self.Name.text = array[itemSelected].valueForKey("Name") as! String
if not just do something with it.
self.Name.text = array[itemSelected] as! String
OR
print(array[itemSelected])

inserting a fake row#indexPath, iOS

Im creating a new table, and within it, Im inserting a new row with fake text, but I get the crash report
Terminating app due to uncaught exception
'NSInternalInconsistencyException', reason: 'attempt to insert row 5
into section 0, but there are only 5 rows in section 0 after the
update
after some fiddling around, I changed my code from:
#IBAction func add() {
let newRow = ChecklistItems(text: "Im the new Row", checked: false)
items.append(newRow)
let index = items.count
let indexPath = NSIndexPath(forRow: index, inSection: 0)
tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Left)
}
TO THIS:
#IBAction func add() {
let index = items.count
let newRow = ChecklistItems(text: "Im the new Row", checked: false)
items.append(newRow)
let indexPath = NSIndexPath(forRow: index, inSection: 0)
tableView.insertRowsAtIndexPaths([indexPath], withRowAnimation: .Left)
}
can someone explain to me the actual details why this switch made the code work?
thank you so much~
Welcome to SO.
In your first version, you add an item to your items array, then create an indexPath which points to the count of the array (So if the array contains 5 items, you create an indexPath value of row:5, section:0)
However, arrays are zero-based. If an array contains 5 elements, valid array indexes are 0 - 4. The same goes for indexPath values. The highest valid row value is totalRows - 1. If the array contains 5 elements, 5 is not a valid array index.
In the second version of your code, index = the item count BEFORE adding an item. So if the row contains 4 items, count = 4, you add an item, and now items contains 5 items and 4 is a valid index into the array, so the insert does not refer to an item that's beyond the end of your items array.
Because the indexPath is beginning with 0, so it's max value is the items.count - 1
Because count is starting from 1, but NSIndexPath and also array index starting from 0.
so lets say you have an array of ("a", "b", "c"), array count is 3. but the index of it is 0, 1, 2.
so with your first code, you add new item and choose the index based on its count which is beyond its array index. for example you add new item "d" to example array above, the count will be changed to 4. But the max index is 3, which is why it throws error.
with your second code, you get the index based on count first before adding. So you set index for item d with 3, because the array only contain a, b, c and then add d to array.
it is working for you right now, but it will potentially create a mismatch between your array index and your tableView index.
A good way to retrieve object index is using array function indexOf.

Resources