Retrieving Information from Specific UICell Using Swift - swift

In my program, I have an UITableView and I need to access a label in one of the UITableViewCells. I have the indexPath for the UITableViewCell, but I was wondering how I should proceed in grabbing the cell's label using Swift. Any ideas on how you access a cell without being in the table view swift file?

You shouldn't go through the cell to grab the content of the label. Instead, you should go through whatever data structures that you used to set that label in the first place.
Go to your tableView:cellForRowAtIndexPath: code, and find the part where you set up the label in the cell
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
cell.textLabel?.text = self.items[indexPath.row] // <<== HERE
return cell
}
You have code similar to the above, where you use the source of data to set up your label from an indexPath. Using the same code to obtain the text that went into your label provides the most direct way of getting the data.

Related

Ads between cells of UITableView which uses Core Data with NSFetchedResultsController

(I have already referred this StackOverflow post, however did not find what I was looking for)
I have a requirement to show ads in between cells of a UITableView.
The image above is used only for representational purposes, and does not show the actual design/data used by the app I am working with.
The normal cells of the UITableView come from a Core Data fetch request via NSFetchedResultsController using fetchController.object(at: indexPath), whereas the ad cells come from a different data source altogether.
Since the ads need to be shown in between the actual table view cells, it messes up the indexPath used by NSFetchedResultsController to retrieve the object from Core Data fetch request.
Also the user has the option to delete any of the actual cells (non-ad cells) from the UITableView, which can in-turn change the indexPath of the cells.
There can be variable number of ads shown in the cells, for now assume it to be a constant c.
Please let me know if there is a way to handle all these edge cases efficiently, preferably without changing the indexPath object used in fetchController.object(at: indexPath).
You can add a flag to your table view cell class, telling if to show an ad or not:
class MyTableViewCell: UITableViewCell {
var showAd: Bool = false {
didSet {
// `adView` here being either an IBOutlet from the XIB,
// or a programatically created view, depending on how
// you designed the cell
adView.isHidden = !showAd
}
}
}
With the above in place, what's left is to store an array of randomly generated indices where you want to show the ads, and update the cell accordingly:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = ...
cell.showAd = adIndices.contains(indexPath.row)
return cell
}

UITableViewCell's attributed text not updating

I have a table view that is connected through a Core Data's NSFetchedResultsControler. The cells have a UILabel with attributed text and a UISwitch representing the object's isEnabled value. Inside the cell, I have a function:
func configure(with viewModel: CellViewModel) {
myCustomLabel.attributedText = viewModel.attributedText // NSMutableAttributedText
}
Chaning the switch changes the isEnabled value on the object, which in cause raises the NSFetchedResultsControler, which calls:
let cell: MyTableViewCell = tableView.dequeueReusableCell(forIndexPath: indexPath) //my custom helper method
let cellViewModel = viewModel.itemModel(at: indexPath)
cell.configure(with: cellViewModel)
I do not want to use reloadData, reloadRows or reloadSections, because I want to keep animations while changing the cell's state and avoid cell fading animation if only switch is flipped. I know this is quite bad approach but it's required to keep the animations.
The problem is: The attributedText doesn't change on the label immediately. Only after cell is reused. The debugger displays the new value of the label correctly. I have tried:
this suggestion (setting font and color to nil beforehand),
calling setNeedDisplay on both the label and it's superview
setting the non-attributed text first, then attributedText
Nothing works. Do you have any ideas why it's like that?
System is iOS 11.4, XCode 9.4.1.
If you wrap myCustomLabel.attributedText = viewModel.attributedText in a DispatchQueue.main.async { } it will work:
DispatchQueue.main.async {
myCustomLabel.attributedText = viewModel.attributedText
}
I think that instead of:
let cell: MyTableViewCell = tableView.dequeueReusableCell(forIndexPath: indexPath)
You should use:
tableView.cellForRow(at: indexPath)
That will return you the cell instance for that indexPath. By calling "dequeueReusableCell" you are essentially saying you want a new Cell.
That assumes that I get what you are trying to achieve and your snippet is not from the
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
method.
If that doesn't work might be worth adding a git link to take a look at your code.
Hope that helps!

create drop down in UITableView swift

I have gotten to the point where I have a selectable list of options, which are all loaded into the same .xib files. I am trying to make it so upon the click on a cell a different .xib file is populated below, and all of the other cells shift down. However, I am unsure of how to have 2 different xib's as TableViewCells in swift.
There's two ways I can think of to accomplish what you are trying to do:
Single xib file: You should use a single xib file that hides the lower section that contains the options until the cell is tapped. When tapped, a property on the UITableCell class could be set, e.g. isExpanded. When isExpanded is set, your cell could unhide the options (by changing constraints).
Multiple xibs: When tapped, you could insert a new item into your datasource. In your cellForRow, you could check for some identifier and load either the regular cell or the options cell using something like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == optionsRow {
let cell = tableView.dequeueReusableCell(withIdentifier: OptionsCellIdentifier, for: indexPath) as! OptionsCell
//Configure cell here
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: NormalCellIdentifier, for: indexPath) as! NormalCell
//Configure cell here
return cell
}
}

Dequeueing TableViewCells from Storyboard Prototype cells?

I have defined a tableView in code within my main ViewController class. I have added that to the main view and also defined a custom tableViewCell in a swift file. I have setup a basic app displaying some datasource information in the single textLabel that comes default with a subclassed UITableViewCell. However, now I want to design a slightly more complicated UI in Interface builder. My ViewController is defined in the Main Storyboard. How do I sync up my pre-existing tableViewCell with a prototype cell view element in storyboard? Filling in the Cell Identifier and the Custom Class with my class, as well as calling dequeueReusableCellWithIdentifier with that identifier and casting the result to my custom type does not seem to give me a cell with the properties loaded up in the storyboard.
Can you show some code you are using?
It should look something like:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("reuseIdentifier", forIndexPath: indexPath) as! CustomCell
return cell
}

Putting multiple type TableViewCells in the same Table View

I have a table view that is currently displaying a type of tableViewCell creating in a XIB File and I want to display a different type of XIB file in the table View at random Places. e.g. Like having Ad display Cells in a tableview at Random Post positions.
How can I do this. I currently have the following code for displaying one Cell:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cardioCell:CardioItemsTableViewCell! = tableView.dequeueReusableCellWithIdentifier("CardioItemsTableViewCell") as? CardioItemsTableViewCell
cardioCell.cellNameLabel.text = "Test String"
return cardioCell!
}
I have this image of the apple news App with one cell without an image. In my instance though, the cell is completely different and has a different layout to the other cells.
Any ideas would be much appreciated.
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if indexPath.row % 2 == 0
let cardioCell:CardioItemsTableViewCell! = tableView.dequeueReusableCellWithIdentifier("CardioItemsTableViewCell") as? CardioItemsTableViewCell
cardioCell.cellNameLabel.text = "Cells with even number of row"
return cardioCell!
else if indexPath.row % 2 != 0
let otherTypeCell:OtherTypeTableViewCell! = tableView.dequeueReusableCellWithIdentifier("OtherTypeItemsTableViewCell") as? OtherTypeTableViewCell
otherTypeCell.cellNameLabel.text = "Cells with odd number of row"
return otherTypeCell!
}
You can not load cells randomly. You need to have a certain logic based on which you can load different types of tableViewCell.