Convert the original tableview to collectionview data cannot be passed - ios

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 }

Related

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!

Reload Tableview using RxSwift

I am using RxSwift for tableview. I need to reload my table each time after getting data from api but I'm failed to do this. I couldn't find any solution for that. Can anybody help?
I have an array of places obtain from response of an Api.I have used this code in view did load, but its is not being called when array is updated.
I have found the issue. My array was not being getting updated correctly. I did the following changes.
Declare dataSource variable of ModelClass:
let dataSource = Variable<[SearchResult]>([])
Bind it with the table view right now it is empty:
dataSource.asObservable().bindTo(ResultsTable.rx.items(cellIdentifier: "SearchCell")){ row,Searchplace,cell in
if let C_cell = cell as? SearchTableViewCell{
C_cell.LocationLabel.text = Searchplace.place
}
}.addDisposableTo(disposeBag)
Then store my updated array in it that contains the searchPlaces:
dataSource.value = self.array
Now each time when value of dataSource will be changed, table view will be reloaded.
Avoid using "Variable" because of this concept will be deprecated from RxSwift but official migration path hasn't been decided yet.
REF: https://github.com/ReactiveX/RxSwift/issues/1501
Hence, recommend using RxCocoa.BehaviorRelay instead.
let dataSource = BehaviorRelay(value: [SearchResultModel]())
Bind to tableView
self.dataSource.bind(to: self.tableView.rx.items(cellIdentifier: "SearchCell", cellType: SearchCell.self)) { index, model, cell in
cell.setupCell(model: model)
}.disposed(by: self.disposeBag)
after fetch data:
let newSearchResultModels: [SearchResultModel] = ..... //your new data
dataSource.accept(newSearchResultModels)
Hope this can help :)
Let
array = Variable<[SearchResult]>([])
Whenever you hit your API, put your fetched results in self.array.value and it will automatically gets updated.
self.array.asObservable().bindTo(ResultsTable.rx.items(cellIdentifier: "SearchCell", cellType:SearchCell.self))
{ (row, element, cell) in
cell.configureCell(element: element)
}.addDisposableTo(disposeBag)

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])

SWIFT: "removeAtIndex" don't work with (sender:UIButton)

#IBOutlet var items: [UIButton]
#IBAction func itemsHidden(sender: UIButton) {
sender.hidden = true
items.removeAtIndex(sender)
}
Hello.
For example, i have array of items.
The code has the error: "Cannot invoke 'removeAtIndex' with an argument list of type (UIButton)".
What i need to do, that "removeAtIndex" works?
Thanks...
A removeAtIndex method expects to get an index as a parameter.
If you want to remove an object use func removeObject(_ anObject: AnyObject)
EDIT
There's no removeObject in a swift's array (only in NSMutableArray).
In order to remove an element, you need to figure out it's index first:
if let index = find(items, sender) {
items.removeAtIndex(index)
}
You don't tell us the class of your items object.
I assume it's an Array. If not, please let us know.
As Artem points out in his answer, removeAtIndex takes an integer index and remove the object at that index. The index must be between zero and array.count-1
There is no removeObject(:) method for Swift Array objects because Arrays can contain the same entry at more than one index. You could use the NSArray method indexOfObject(:) to find the index of the first instance of your object, and then removeAtIndex.
If you're using Swift 2, you could use the indexOf(:) method, passing in a closure to detect the same object:
//First look for first occurrence of the button in the array.
//Use === to match the same object, since UIButton is not comparable
let indexOfButton = items.indexOf{$0 === sender}
//Use optional binding to unwrap the optional indexOfButton
if let indexOfButton = indexOfButton
{
items.removeAtIndex(indexOfButton)
}
else
{
print("The button was not in the array 'items'.");
}
(I'm still getting used to reading Swift function definitions that include optionals and reference protocols like Generator so the syntax of the above may not be perfect.)

Int is not convertible to 'Range<Int>'

I have a custom UITableViewCell, which contains a UIButton(upVoteButtonPressed) and a UILabel (voteScoreLabel).
In order to get the numerical scores to show up in the labels of the UITableView, the array that contains that the number of votes is a String array, although its contents are in actuality integers.
The tag of the label has been set in the tableview controller to be the same as the indexPath.row. This lets me pick a particular item in the array.
However when I want to add a specific value, add 1 for example, I cannot because when I try to execute the following code I get the following error: Int is not convertible to 'Range'.
The code below is in my custom UITableViewCell. My goal is to pick out a particular value of the array, convert it to an integer and then add 1 to it. What does this mean and how can I fix it.
#IBAction func upVoteButtonPressed(sender: AnyObject) {
groupVote[voteScoreLabel.tag]=groupVote[voteScoreLabel.tag].toInt()
}
Edit
The solution suggested in the comments to make the array type int, and then when putting into the tableview to convert to string has worked. Problem Solved.
Make the array type an int because the array is currently seen as a String type array and that is backwards and inefficient. Then when putting the array values into the UITableView use label.text = "(theIntValue)" to convert the int values into strings.

Resources