UITableViewCell size does not change - ios

I cannot understand why the cells do not resize according to the given .xib file
This is my table controller
import Foundation
import UIKit
class RecipeTableView: UIViewController {
let cellIdentifier = "RecipeTableViewCell"
#IBOutlet weak var recipeTableView: UITableView!
private let localDatabaseManager: LocalDatabaseManager = LocalDatabaseManager.shared
private var recipes = [Recipe]()
override func viewDidLoad() {
super.viewDidLoad()
recipeTableView.dataSource = self
recipeTableView.delegate = self
//recipeTableView.rowHeight = UITableView.automaticDimension
//recipeTableView.estimatedRowHeight = UITableView.automaticDimension
self.recipeTableView.register(UINib(nibName: cellIdentifier, bundle: nil), forCellReuseIdentifier: cellIdentifier)
localDatabaseManager.loadRecipes { [weak self] (recipes) in
guard let recipes = recipes else {
return
}
self?.recipes = recipes
DispatchQueue.main.async {
self?.recipeTableView.reloadData()
}
}
}
// override func viewWillAppear(_ animated: Bool) {
// recipeTableView.estimatedRowHeight = 256
// recipeTableView.rowHeight = UITableView.automaticDimension
// }
}
extension RecipeTableView: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
recipes.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as? RecipeTableViewCell else {
return UITableViewCell()
}
let recipe = recipes[indexPath.row]
cell.configure(with: recipe)
//cell.layer.cornerRadius = 32
//cell.layer.masksToBounds = true
return cell
}
}
extension RecipeTableView: UITableViewDelegate {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
}
And my cell swift file
import Foundation
import UIKit
import Kingfisher
import Cosmos
class RecipeTableViewCell: UITableViewCell {
#IBOutlet weak var recipeNameLabel: UILabel!
#IBOutlet weak var recipeDescriptionLabel: UILabel!
#IBOutlet weak var recipeImageView: UIImageView!
#IBOutlet weak var recipeCosmosView: CosmosView!
override func prepareForReuse() {
super.prepareForReuse()
recipeNameLabel.text = nil
recipeDescriptionLabel.text = nil
recipeImageView.image = nil
}
func configure(with recipe: Recipe) {
recipeNameLabel?.text = recipe.name
recipeDescriptionLabel?.text = recipe.description
//let imageBytes = recipe.imageData
//let imageData = NSData(bytes: imageBytes, length: imageBytes.count)
//let image = UIImage(data: imageData as Data)
//recipeImageView?.image = image
let imageUrl = URL(string: recipe.imageData)
recipeImageView?.kf.setImage(with: imageUrl)
recipeCosmosView.settings.fillMode = .precise
recipeCosmosView.rating = recipe.rating
}
}
here is what my custom cell looks like
here is how these cells are shown in the app
I already found similar questions, but everywhere the same answer. Need to add the following lines. So I tried.
override func viewWillAppear(_ animated: Bool) {
recipeTableView.estimatedRowHeight = 256
recipeTableView.rowHeight = UITableView.automaticDimension
}
But it did not work

I think you need to call another tableView method for set the height for each cell according to his content
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// add estimated height here ....
//...
return indexPath.row * 20
}

Related

DidSelectRowAt won't return desired item

I have dynamic table which displays a number of MKMapItems - these items are being displayed by cellForRowAt. But somehow if I click on the cell didSelectRow won't return the map item if I want to print it:
class SearchResultTableViewController: UIViewController {
#IBOutlet weak var searchBar: UISearchBar!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var visualEffectView: UIVisualEffectView!
private enum SegueID: String {
case showDetail
case showAll
}
private enum CellReuseID: String {
case resultCell
}
private var places: [MKMapItem]? {
didSet {
tableView.reloadData()
}
}
private var suggestionController: SuggestionsTableTableViewController!
var searchController: UISearchController!
private var localSearch: MKLocalSearch? {
willSet {
places = nil
localSearch?.cancel()
}
}
private var boundingRegion: MKCoordinateRegion?
override func awakeFromNib() {
super.awakeFromNib()
...
}
override func viewDidLoad() {
super.viewDidLoad()
...
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if #available(iOS 10, *) {
visualEffectView.layer.cornerRadius = 9.0
visualEffectView.clipsToBounds = true
}
}
...
}
extension SearchResultTableViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return places?.count ?? 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseID.resultCell.rawValue, for: indexPath)
if let mapItem = places?[indexPath.row] {
cell.textLabel?.text = mapItem.name
cell.detailTextLabel?.text = mapItem.placemark.formattedAddress
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
print(indexPath)
...
guard let mapItem = places?[indexPath.row] else { return }
print(mapItem.name)
...
if tableView == suggestionController.tableView, let suggestion = suggestionController.completerResults?[indexPath.row] {
searchController.isActive = false
searchController.searchBar.text = suggestion.title
search(for: suggestion)
}
}
}
guard let mapItem = places?[indexPath.row] else { return }
- are you sure this guard statement isn't returning?
also, I'm not seeing where you're setting the VC as the tableView delegate/datasource.

can we pass data from table cell to table view where both are xib files?

I want to pass table cell data (xib file) to table view (also a xib file). I have tried passing the data using the following piece of code but did not get an appropriate result.
PropertyCell.swift
import UIKit
class PropertyCell: UITableViewCell {
#IBOutlet weak var propertyCodeLbl: UILabel!
#IBOutlet weak var addressLbl: UILabel!
}
I have attached the screenshot for PropertyCell below -
PropertyCell.xib
PropertyCell.xib file
PropertyTableVC.swift
import UIKit
import Alamofire
class PropertyTableVC: UITableViewController {
#IBOutlet var propertyTabel: UITableView!
let URL_Landlord_Property_List = "http://127.0.0.1/source/api/LandlordPropertyList.php"
var count: Int = 0
var landlordPropertyArray: [PropertyList]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
propertyTabel.dataSource = self
propertyTabel.delegate = self
let nibName = UINib(nibName: "PropertyCell", bundle:nil)
self.propertyTabel.register(nibName, forCellReuseIdentifier: "Cell")
}
func fetchData(){
let urlRequest = URLRequest(url: URL(string: URL_Landlord_Property_List)!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error != nil{
print(error!)
return
}
print(data!)
self.landlordPropertyArray = [PropertyList]()
self.count = (self.landlordPropertyArray?.count)!
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let datafromjson = json["landlords_property_list"] as? [[String: AnyObject]] {
print(datafromjson)
for data in datafromjson{
var property = PropertyList()
if let id = data["ID"] as? Int,let code = data["Code"] as? String, let address1 = data["Address"] as? String
{
property.id = id
property.code = code
property.address1 = address1
}
self.landlordPropertyArray?.append(property)
}
print(self.landlordPropertyArray)
}
DispatchQueue.main.async {
self.propertyTabel.reloadData()
}
}catch let error {
print(error)
}
}
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (landlordPropertyArray?.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PropertyCell
cell.propertyCodeLbl.text = self.landlordPropertyArray?[indexPath.item].code
cell.addressLbl.text = self.landlordPropertyArray?[indexPath.item].address1
return cell
}
}
Attached the screenshot for Property Table below -
PropertyTableVC.xib
PropertyTableVC.xib file
Your TableViewCell :
import UIKit
protocol yourProtocolName { //add protocol here
func getDataFromTableViewCellToViewController (sender : self) //* as you need to pass the table view cell, so pass it as self
}
class PropertyCell: UITableViewCell {
#IBOutlet weak var propertyCodeLbl: UILabel!
#IBOutlet weak var addressLbl: UILabel!
var delegate : yourProtocolName? //set a delegate
override func awakeFromNib() {
super.awakeFromNib()
if delegate != nil {
delegate.getDataFromTableViewCellToViewController(sender :self) *
}
}
}
And your ViewController :
import UIKit
import Alamofire
class PropertyTableVC: UITableViewController,yourProtocolName { //conform to the protocol you created in tableViewCell
#IBOutlet var propertyTabel: UITableView!
let URL_Landlord_Property_List = "http://127.0.0.1/source/api/LandlordPropertyList.php"
var count: Int = 0
var landlordPropertyArray: [PropertyList]? = []
override func viewDidLoad() {
super.viewDidLoad()
fetchData()
propertyTabel.dataSource = self
propertyTabel.delegate = self
let nibName = UINib(nibName: "PropertyCell", bundle:nil)
self.propertyTabel.register(nibName, forCellReuseIdentifier: "Cell")
}
func fetchData(){
let urlRequest = URLRequest(url: URL(string: URL_Landlord_Property_List)!)
let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in
if error != nil{
print(error!)
return
}
print(data!)
self.landlordPropertyArray = [PropertyList]()
self.count = (self.landlordPropertyArray?.count)!
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String: AnyObject]
if let datafromjson = json["landlords_property_list"] as? [[String: AnyObject]] {
print(datafromjson)
for data in datafromjson{
var property = PropertyList()
if let id = data["ID"] as? Int,let code = data["Code"] as? String, let address1 = data["Address"] as? String
{
property.id = id
property.code = code
property.address1 = address1
}
self.landlordPropertyArray?.append(property)
}
print(self.landlordPropertyArray)
}
DispatchQueue.main.async {
self.propertyTabel.reloadData()
}
}catch let error {
print(error)
}
}
task.resume()
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return (landlordPropertyArray?.count)!
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
// Configure the cell...
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! PropertyCell
cell.propertyCodeLbl.text = self.landlordPropertyArray?[indexPath.item].code
cell.addressLbl.text = self.landlordPropertyArray?[indexPath.item].address1
return cell
}
func getDataFromTableViewCellToViewController(sender :UITableViewCell) {
//make a callback here
}
}
(*) Marked fields are updated code
Call fetchData() function after tableview delegate and datasource assigning
propertyTabel.dataSource = self
propertyTabel.delegate = self
Updated answer is
Create Cell Class like this
import UIKit
class YourTableViewCell: UITableViewCell {
#IBOutlet weak var profileImageView: UIImageView!
#IBOutlet weak var userNameLabel: UILabel!
#IBOutlet weak var timeDateLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
self.backgroundColor = UIColor.tableViewBackgroundColor()
self.selectionStyle = .none
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
class func cellForTableView(tableView: UITableView, atIndexPath indexPath: IndexPath) -> YourTableViewCell {
let kYourTableViewCell = "YourTableViewCellIdentifier"
tableView.register(UINib(nibName:"RRLoadQuestionsTableViewCell", bundle: Bundle.main), forCellReuseIdentifier: kYourTableViewCell)
let cell = tableView.dequeueReusableCell(withIdentifier: kYourTableViewCell, for: indexPath) as! YourTableViewCell
return cell
}
}
Then create UIViewController Class and place UITableView on it and link with outlet
class YourViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextViewDelegate {
#IBOutlet weak var tableView: UITableView!
var dataSource = [LoadYourData]()
// MARK: - Init & Deinit
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
super.init(nibName: "YourViewController", bundle: Bundle.main)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
NotificationCenter.default.removeObserver(self)
}
override func viewDidLoad() {
super.viewDidLoad()
setupViewControllerUI()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
}
// MARK: - UIViewController Helper Methods
func setupViewControllerUI() {
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.delegate = self
tableView.dataSource = self
loadData()
}
func loadData() {
// Write here your API and reload tableview once you get response
}
// MARK: - UITableView Data Source
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return dataSource.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = YourTableViewCell.cellForTableView(tableView: tableView, atIndexPath: indexPath)
// assign here cell.name etc from dataSource
return cell
}

Can't call object from another class

I have a table view with expanding cells. The expanding cells come from a xib file. In the class of the table is where all of the code is that controls the expansion and pulling data from plist. I'm trying to add a close button but only want it to show when the cell is expanded. As it stands, I can't reference the button to hide it because it's in another class. Here is how I am trying to access it:
import UIKit
class SecondPolandViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var customTableViewCell:CustomTableViewCell? = nil
var items = [[String:String]]()
override func viewDidLoad() {
super.viewDidLoad()
**REFERENCING CLASS**
customTableViewCell = CustomTableViewCell()
let nib = UINib.init(nibName: "CustomTableViewCell", bundle: nil)
self.tableView.register(nib, forCellReuseIdentifier: "cell")
self.items = loadPlist()
}
func loadPlist()->[[String:String]]{
let path = Bundle.main.path(forResource: "PolandResourceList", ofType: "plist")
return NSArray.init(contentsOf: URL.init(fileURLWithPath: path!)) as! [[String:String]]
}
var selectedIndex:IndexPath?
var isExpanded = false
func didExpandCell(){
self.isExpanded = !isExpanded
self.tableView.reloadRows(at: [selectedIndex!], with: .automatic)
}
}
extension SecondPolandViewController:UITableViewDataSource, UITableViewDelegate{
***HIDING BUTTON***
let button = customTableViewCell?.closeButton
button?.isHidden = true
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath
self.didExpandCell()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
cell.selectionStyle = .none
let item = self.items[indexPath.row]
cell.titleLabel.text = item["title"]
cell.shortLabel.text = item["short"]
cell.otherImage.image = UIImage.init(named: item["image"]!)
cell.thumbImage.image = UIImage.init(named: item["image"]!)
cell.longLabel.text = item["long"]
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let height = UIScreen.main.bounds.height
if isExpanded && self.selectedIndex == indexPath{
//return self.view.frame.size.height * 0.6
return 400
}
return 110
//return height * 0.2
}
}
This does not hide it though.
Here is the xib that I am calling from if it helps. It is probably simple, I am just a newly self taught developer.
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var closeButton: UIImageView!
#IBOutlet weak var otherImage: UIImageView!
#IBOutlet weak var thumbImage: UIImageView!
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var shortLabel: UILabel!
//#IBOutlet weak var longLabel: UITextView!
#IBOutlet weak var longLabel: UITextView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
//let width = UIScreen.main.bounds.width
//let height = UIScreen.main.bounds.height
//thumbImage.frame.size.width = height * 0.19
//thumbImage.frame.size.height = height * 0.19
}
}
It seems like that you just need to add these lines into cellForRowAt:indexPath method:
if indexPath == selectedIndexPath {
cell.closeButton.isHidden = false
} else {
cell.closeButton.isHidden = true
}
You may add them right before return line
The normal iOS answer for this is a delegate, but you could get away with a simple closure in this case.
In CustomTableViewCell, add
public var closeTapped: ((CustomTableViewCell) -> ())?
Then in that class, when close is tapped, call
self.closeTapped?(self)
In the VC, in cellForRowAt,
cell.closeTapped = { cell in
// do what you want with the VC
}
For delegates, this might help: https://medium.com/#jamesrochabrun/implementing-delegates-in-swift-step-by-step-d3211cbac3ef
The quick answer to why to prefer delegates over the closure is that its a handy way to group a bunch of these together. It's what UITableViewDelegate is (which you are using). Also, it's a common iOS idiom.
I wrote about this here: https://app-o-mat.com/post/how-to-pass-data-back-to-presenter for a similar situation (VC to VC communication)

Gets number of rows but doesn't print

I have a program written in Swift 3, that grabs JSON from a REST api and appends it to a table view.
Right now, I'm having troubles with getting it to print in my Tableview, but it does however understand my count function.
So, I guess my data is here, but it just doesn't return them correctly:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, HomeModelProtocal {
#IBOutlet weak var listTableView: UITableView!
func itemsDownloaded(items: NSArray) {
feedItems = items
self.listTableView.reloadData()
}
var feedItems: NSArray = NSArray()
var selectedLocation : Parsexml = Parsexml()
override func viewDidLoad() {
super.viewDidLoad()
self.listTableView.delegate = self
self.listTableView.dataSource = self
let homeModel = HomeModel()
homeModel.delegate = self
homeModel.downloadItems()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cellIdentifier: String = "BasicCell"
let myCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier)!
let item: Parsexml = feedItems[indexPath.row] as! Parsexml
myCell.textLabel!.text = item.title
return myCell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return feedItems.count
}
override func viewDidAppear(_ animated: Bool) {
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
}
Are you by any chance able to see the error that I can't see?
Note. I have not added any textlabel to the tablerow, but I guess that there shouldn't be added one, when its custom?
Try this code:
override func viewDidLoad() {
super.viewDidLoad()
print(yourArrayName.count) // in your case it should be like this print(feedItems.count)
}

Sort cell input from customized cell in viewController

I have a ViewController in which a tableView and a button "sort" is integrated.
The cells of this tableView are customized in another class called "customizedCell".
When the ViewController is loaded, a label (riskTitle: UITextView! in CellCustomized) in the tableView is filled with the items stored in the array (RiskTitles_Plan = String in ViewController). My code below has some values hard coded for this array.
What I am trying to do now is to store the numbers generated by two pickerViews in the label "riskFactor: UILabel!" in an array (RiskFactor_Plan -> RiskFactor_Int). When the user clicks on the button sort, the values in my array have to be sorted and the rows in the tableView will be loaded in a new order (smallest to biggest number or vise versa).
This is my code (unnecessary code is deleted).
Swift 3 - ViewController:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var RiskTitles_Plan = [String]()
var RiskFactor_Plan = [String]()
var RiskFactor_Plan_Int = [Int]()
var sortBtn = UIButton()
override func viewDidLoad() {
super.viewDidLoad()
RiskTitles_Plan = ["my cat","my dog","my sheep","my cow","my fish"]
sortBtn.setImage(UIImage(named: "Sort"), for: UIControlState.normal)
sortBtn.addTarget(self, action: #selector(RiskPlan.sortAction(_:)), for: .touchUpInside)
self.view.addSubview(sortBtn)
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return RiskTitles_Plan.count
}
/////// Here comes the interesting part ///////
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView!.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CellCustomized
RiskFactor_Plan.append(cell.riskFactor.text!)
cell.riskTitle?.text = RiskTitles_Plan[indexPath.row]
cell.backgroundColor = myColorsClass.darkCyan()
for i in RiskFactor_Plan_Int {
let stringItem: String = String(i)
RiskFactor_Plan.append(stringItem)
}
cell.riskFactor.text! = RiskFactor_Plan[indexPath.row]
return cell
}
func sortAction(_ sender:UIButton!) {
for i in RiskFactor_Plan {
let intItem: Int = Int(i)!
RiskFactor_Plan_Int.append(intItem)
}
RiskFactor_Plan_Int = RiskFactor_Plan_Int.sorted{ $0 < $1 }
tableView.reloadData()
}
}
Swift 3 - CellCustomized:
import UIKit
class CellCustomized: UITableViewCell {
var myColorsClass = myColors()
var myStylesClass = myStyles()
#IBOutlet weak var riskTitle: UITextView!
#IBOutlet weak var riskFactor: UILabel!
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) // the common code is executed in this super call
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
} // nib end
}
The code above results in the error fatal error: unexpectedly found nil while unwrapping an Optional value for code line: let intItem: Int = Int(i)! in ViewController when the sort button in clicked.
My problem is to figure out
how to save the generated values in riskFactor: UILabel! in an array (-> RiskTitles_Plan = String) during runtime. I guess the array needs to be appended whenever the label in the table is updated with a generated value
how to convert the string array (-> RiskTitles_Plan = String) to an integer array (-> RiskTitles_Plan_Int = Int)
Based on the context of your problem I tried to replicate in a project so this is how I do it, hopefully it can help you.
Result:
Code:
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
#IBOutlet weak var tableView: UITableView!
var risks = Array<(title: String, factor: Int)>()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
risks.append(("my cat", 0))
risks.append(("my dog", 0))
risks.append(("my sheep", 0))
risks.append(("my cow", 0))
risks.append(("my fish", 0))
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return risks.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
let riskTitle = risks[indexPath.row].title
let riskFactor = risks[indexPath.row].factor
cell.titleLabel.text = riskTitle
cell.factorLabel.text = String(riskFactor)
cell.index = indexPath.row
cell.onFactorValueChanged = { [unowned self] newFactorValue, atIndex in
self.risks[atIndex].factor = newFactorValue
}
return cell
}
#IBAction func sortRisksBasedOnFactor(_ sender: AnyObject) {
risks.sort { (riskA, riskB) -> Bool in
return riskA.factor > riskB.factor
}
tableView.reloadData()
}
}
class TableViewCell: UITableViewCell {
#IBOutlet weak var titleLabel: UILabel!
#IBOutlet weak var factorLabel: UILabel!
var index = 0
var onFactorValueChanged: (Int, Int) -> Void = { _ in }
#IBAction func generateFactor(_ sender: AnyObject) {
factorLabel.text = String(random(min: 1, max: 10))
onFactorValueChanged(Int(factorLabel.text!)!, index)
}
func random(min: Int, max: Int) -> Int {
guard min < max else {return min}
return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}
}

Resources