How to use KVO to update tableViewCells based on underlying array element changes? - ios

I have a table view representing an underlying array. The cells have a label and a slider which should show the value of the percentage property of the array.
I want to use key-value observing to update the label whenever the percentage property changes. (I know KVO is overkill in this example but eventually sliding one slider will affect the other cells including the position of the slider and the underlying array will be set from multiple places in the app and at any time so KVO is the way to go.)
I've had a bunch of help from this answer, but I can't get it to fire and update the label. I'm including all my code here. Not sure where I'm going wrong.
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, CustomCellDelegate {
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.delegate = self
for i in 0...4 {
items.append(Items(ID: i, percentage: 50))
}
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
cell.object = items[indexPath.row]
cell.mySlider.tag = indexPath.row
return cell
} else {
return UITableViewCell()
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
#IBAction func sliderValueChanged(_ sender: UISlider) {
items[sender.tag].percentage = Double(sender.value)
print("percentage at \(items[sender.tag].ID) is \(items[sender.tag].percentage)")
}
func didUpdateObject(for cell: UITableViewCell) {
if let indexPath = tableView.indexPath(for: cell) {
tableView.reloadRows(at: [indexPath], with: .automatic)
print("hello")
}
}
}
class myTableViewCell: UITableViewCell {
static let ID = "myCell"
weak var delegate: CustomCellDelegate?
private var token: NSKeyValueObservation?
var object: Items? {
willSet {
token?.invalidate()
}
didSet {
myLabel.text = "\(object?.percentage ?? 0)"
token = object?.observe(\.percentage) { [weak self] object, change in
if let cell = self {
cell.delegate?.didUpdateObject(for: cell)
}
}
}
}
override func awakeFromNib() {
super.awakeFromNib()
}
#IBOutlet weak var myLabel: UILabel!
#IBOutlet weak var mySlider: UISlider!
}
class Items: NSObject {
let ID: Int
#objc dynamic var percentage: Double
init(ID: Int, percentage: Double){
self.ID = ID
self.percentage = percentage
super.init()
}
}
var items: [Items] = []
protocol CustomCellDelegate: class {
func didUpdateObject(for cell: UITableViewCell)
}

To do the KVO in Swift 4, you have to declare the property as dynamic and call observe(_:options:changeHandler:) on that object, saving the resulting NSKeyValueObservation token. When that token falls out of scope (or replaced with another token), the original observer will automatically be removed.
In your case, you have your observer calling the delegate, which then reloads the cell. But you never appear to set that delegate property, so I suspect that method isn't getting called.
But this all seems a bit fragile. I'd be inclined to just update the label directly in the observer's changeHandler. I also think you can do a more direct updating of the cell (I'd put the "value changed" IBAction in the cell, not the table view), and eliminate that rather awkward use of the tag to identify which row in the model array had its slider updated (which can be problematic if you insert or delete rows).
So consider this object:
class CustomObject: NSObject {
let name: String
#objc dynamic var value: Float // this is the property that the custom cell will observe
init(name: String, value: Float) {
self.name = name
self.value = value
super.init()
}
}
You could then have a table view controller that populates an array of objects with instances of this model type. The details here are largely unrelated to the observation (which we'll cover below), but I include this just to provide a complete example:
class ViewController: UITableViewController {
var objects: [CustomObject]!
override func viewDidLoad() {
super.viewDidLoad()
// self sizing cells
tableView.estimatedRowHeight = 60
tableView.rowHeight = UITableViewAutomaticDimension
// populate model with random data
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
objects = (0 ..< 1000).map {
CustomObject(name: formatter.string(for: $0)!, value: 0.5)
}
}
}
// MARK: - UITableViewDataSource
extension ViewController {
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return objects?.count ?? 0
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.object = objects[indexPath.row]
return cell
}
}
Having done that, you can now have the base class for your cell (a) update the model object if the slider changes; and (b) observe changes to that dynamic property, in this example updating the label when the value changes are observed in the model object:
class CustomCell: UITableViewCell {
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var valueLabel: UILabel!
#IBOutlet weak var valueSlider: UISlider!
static private let formatter: NumberFormatter = {
let _formatter = NumberFormatter()
_formatter.maximumFractionDigits = 2
_formatter.minimumFractionDigits = 2
_formatter.minimumIntegerDigits = 1
return _formatter
}()
private var token: NSKeyValueObservation?
weak var object: CustomObject? {
didSet {
let value = object?.value ?? 0
nameLabel.text = object?.name
valueLabel.text = CustomCell.formatter.string(for: value)
valueSlider.value = value
token = object?.observe(\.value) { [weak self] object, change in
self?.valueLabel.text = CustomCell.formatter.string(for: object.value)
}
}
}
#IBAction func didChangeSlider(_ slider: UISlider) {
object?.value = slider.value
}
}
That yields:
For more information, see the "Key-Value Observing" section of the Using Swift with Cocoa and Objective-C: Adopting Cocoa Patterns.

hi #sean problem is in UITableview cell class you have already make diSet Method , so you dont need to pass value for cell.lable and slider Just try below code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: myTableViewCell.ID) as? myTableViewCell {
//pass the object to which you wanna add observer to cell
cell.object = items[indexPath.row]
return cell
} else {
return UITableViewCell()
}
}

Related

How to pass stepper value to ViewController?

I have a custom cell that has 2 labels, myLabel and numLabel, and a stepper. I have my custom cell in a Swift file and XIB file. I want when I click + or - button on the stepper, my numLabel change with the value of the stepper. I don't know how to pass the stepper value to the viewController where I have my tableView. Later want to save the stepper value to CoreDate how can I do that?. I'm just a beginner. Thank you for helping.
MyCell.swift
import UIKit
class MyCell: UITableViewCell {
static let identifier = "MyCell"
static func nib() -> UINib {
return UINib(nibName: "MyCell", bundle: nil)
}
public func configure(with name: String, number: String) {
myLabel.text = name
numLabel.text = number
}
#IBOutlet var myLabel: UILabel!
#IBOutlet var numLabel: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
ViewController.swift
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.register(MyCell.nib(), forCellReuseIdentifier: MyCell.identifier)
table.delegate = self
table.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.identifier, for: indexPath) as! MyCell
cell.configure(with: "Item 1", number: "1")
return cell
}
}
My Screen Shot
You can do this easily with a "callback" closure:
class MyCell: UITableViewCell {
static let identifier: String = "MyCell"
#IBOutlet var myStepper: UIStepper!
#IBOutlet var numLabel: UILabel!
#IBOutlet var myLabel: UILabel!
// "callback" closure - set my controller in cellForRowAt
var callback: ((Int) -> ())?
public func configure(with name: String, number: String) {
myLabel.text = name
numLabel.text = number
}
#IBAction func stepperChanged(_ sender: UIStepper) {
let val = Int(sender.value)
numLabel.text = "\(val)"
// send value back to controller via closure
callback?(val)
}
static func nib() -> UINib {
return UINib(nibName: "MyCell", bundle: nil)
}
}
Then, in cellForRowAt:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.identifier, for: indexPath) as! MyCell
cell.configure(with: "Item 1", number: "1")
// set the "callback' closure
cell.callback = { (val) in
print("Stepper in cell at \(indexPath) changed to: \(val)")
// do what you want when the stepper value was changed
// such as updating your data array
}
return cell
}
Use a delegate for a generic approach. This allows flexibility in how your cell interacts with the tableview, and enables type checking as you would expect from Swift.
Typically, for a UITableView, you would have an array of data that drives the content of the cells. In your case, let's assume that it's MyStruct (inside your view controller):
struct MyStruct {
let name: String
var value: Int
}
var myStructs: [ MyStruct ] = [
MyStruct( name: "Name 1", value: 1 ),
MyStruct( name: "Name 2", value: 2 ),
MyStruct( name: "Name 3", value: 3 ) ]
Create MyCellDelegate, and place in it whatever methods that you require to communicate changes from the cell to the view controller. For example:
protocol MyCellDelegate: class {
func didSet( value: Int, for myStructIndex: Int )
}
class MyCell: UITableViewCell {
weak var delegate: MyCellDelegate!
var myStructIndex: Int!
...
}
For your table view, assign the delegate when dequeuing the cell, and implement the protocol.
class ViewController: MyCellDelegate, UITableViewDelegate, UITableViewDataSource {
func tableView( _ tableView: UITableView, cellForRowAt indexPath: IndexPath ) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: MyCell.identifier, for: indexPath) as! MyCell
let myStruct = myStructs[indexPath.row] // You may want to ensure that you are in bounds
cell.delegate = self
cell.myStructIndex = indexPath.row
cell.configure( with: myStruct.name, number: myStruct.value )
return cell
}
func didSet( value: Int, for myStructIndex: Int ) {
// Now MyViewController sees the change.
myStructs[myStructIndex].value = value
}
}
Lastly, in your MyCell, whenever the value changes, for example in your stepper, invoke:
#IBAction func stepperChanged( _ sender: UIStepper ) {
let integerValue = Int( sender.value.round() )
numLabel.text = "\(integerValue)"
// Tell the view controller about the change: what happened, and to what cell.
self.delegate.didSet( value: integerValue, for: self.myStructIndex )
}

UISwitch in custom UITableViewCell Reuse Issue

The issue is as follows: I have a tableview with a custom cell. That cell contains a label and a UISwitch. I have set the label.text value to an array, but the UISwitch is getting reused.
Example: If I toggle the switch in the first row, the 5th row gets enabled, and if I scroll it continues to reuse the cells and cause issue.
Video : https://vimeo.com/247906440
View Controller:
class ViewController: UIViewController {
let array = ["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
#IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
cell.label.text = array[indexPath.row]
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
}
Custom Cell:
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var label: UILabel!
#IBOutlet weak var toggleSwitch: UISwitch!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
}
I realize there isn't code trying to store this data because I haven't been successful. Any ideas would be helpful. The project currently uses the MVC model and I believe that is the answer but just need some help.
I would recommend to you create cellViewModel class and keep array of it instead of just string. You cellViewModel may look like,
class CellViewModel {
let title: String
var isOn: Bool
init(withText text: String, isOn: Bool = false /* you can keep is at by default false*/) {
self.title = text
self.isOn = isOn
}
Now, build array of CellViewModel
let array =["One","Two","Three","Four","Five","Six","Seven","Eight","Nine","Ten"]
var cellViewModels = [CellViewModel]()
for text in array {
let cellViewModel = CellViewModel(withText: text)
cellViewModels.append(cellViewModel)
}
Change your tableVieDelegate function to :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
let cellViewModel = cellViewModels[indexPath.row]
cell.label.text = cellViewModel.title
cell.toggleSwitch.isOn = cellViewModel.isOn
cell.delegate = self
return cell
}
In you Custom Cell class, add this protocol :
protocol CellActionDelegate: class {
func didChangeSwitchStateOnCell(_ cell: CustomTableViewCell)
}
Add delegate as property in your custom cell,
weak var delegate: CellActionDelegate?
Also, on switch change, add this line,
delegate?.didChangeSwitchStateOnCell(self)
Now, your viewController should register and listen to this delegate :
I have added line cellForRowAtIndexPath to register for delegates. To listen this delegate, add this function in your VC.
func didChangeSwitchStateOnCell(_ cell: CustomTableViewCell) {
let indexPath = tableView.indexPath(for: cell)
cellViewModels[indexPath.row].isOn = cell.toggleSwitch.isOn
}
start creating a model for example :
struct item {
var id: String
var name: String
var isActivated: Bool
init(id: String, name: String, isActivated: Bool) {
self.id = id
self.name = name
self.isActivated = isActivated
}
}
let item1 = item(id: "1", name: "One", isActivated: false)
let item2 = ...........
let item3 = ...........
let items [item1, item2, item3]
With that you can trigger the boolean if it's activated or not.
You will also have to take a look to https://developer.apple.com/documentation/uikit/uitableviewcell/1623223-prepareforreuse I think.

Loop through a uitableviewcell on submit in swift 4

I am trying to access each value of a text field in a prototype cell within a UITableView on Submit. I know I should be doing this in a better way (model) but for now, I just need to access these fields and cannot find a way to do this in Swift 3/4. Would anyone be able to assist?
Code:
import UIKit
import Firebase
class FormTableViewController: UITableViewController {
var formLabels = [String]()
var formPlaceholders = [String]()
override func viewDidLoad() {
super.viewDidLoad()
FirebaseApp.configure()
formLabels = ["Name","Email","Password", "Phone"]
formPlaceholders = ["John Smith","example#email.com","Enter Password", "8585551234"]
tableView.estimatedRowHeight = 30
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return formLabels.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier:
"FormTableCell", for: indexPath)
as! FormTableViewCell
let row = indexPath.row
cell.formLabel.font =
UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
cell.formLabel.text = formLabels[row]
cell.formTextField.placeholder = formPlaceholders[row]
return cell
}
#IBAction func submitButtonPressed(_ sender: Any) {
// Need to do something with the Name, Email, Phone and Password fields here
}
}
You seem to acknowledge that updating the model directly probably makes sense. So why not do that? Just:
Have model collection for the responses;
Set up delegate for the text field in the cell;
Have cellForRowAt set that delegate; and
Make the table view controller conform to that class.
So, something quick and dirty, set up the cell to hook up editChanged event from the text field and set up protocol to inform the view controller:
protocol FormTableViewCellDelegate: class {
func fieldValueChanged(cell: UITableViewCell, textField: UITextField)
}
class FormTableViewCell: UITableViewCell {
weak var delegate: FormTableViewCellDelegate?
#IBOutlet weak var formLabel: UILabel!
#IBOutlet weak var formTextField: UITextField!
#IBAction func editingChanged(_ sender: UITextField) {
delegate?.fieldValueChanged(cell: self, textField: sender)
}
}
And then have the view controller set up model object and conform to your new protocol:
class FormTableViewController: UITableViewController {
var formLabels = [String]()
var formPlaceholders = [String]()
var values = [String?]()
override func viewDidLoad() {
super.viewDidLoad()
...
formLabels = ["Name","Email","Password", "Phone"]
formPlaceholders = ["John Smith","example#email.com","Enter Password", "8585551234"]
values = [nil, nil, nil, nil]
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "FormTableCell", for: indexPath) as! FormTableViewCell
let row = indexPath.row
cell.formLabel.font = .preferredFont(forTextStyle: .headline)
cell.formLabel.text = formLabels[row]
cell.formTextField.placeholder = formPlaceholders[row]
cell.formTextField.text = values[row]
cell.delegate = self // set the delegate, too
return cell
}
#IBAction func submitButtonPressed(_ sender: Any) {
print(#function, values)
}
}
// delegate protocol to update model as text fields change
extension FormTableViewController: FormTableViewCellDelegate {
func fieldValueChanged(cell: UITableViewCell, textField: UITextField) {
guard let indexPath = tableView.indexPath(for: cell) else { return }
values[indexPath.row] = textField.text
}
}
Then that's it, your model is updated as the text fields are updated. Plus this has the advantage that it now supports cell reuse, conforms to MVC patterns, etc.
If you want to just loop through cells, you can create an array of ‘IndexPath’.
let array = (0..<formLabels.count).map { IndexPath(row: $0, section:0) }
After that you can loop over this array and access individual cell using tableview method:- tableView.cellForIndexPath
Hope this helps. (Not on my laptop, so didn’t test the syntax)

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
}
}

iOS Swift Dequeued Reusable Cell not showing up

I followed a tutorial earlier to get the basics of the Storyboard down and I'm using that code as a reference to write the app I'm working on. I want to test my prototype cell layout, but even though I set a value to the array at viewDidLoad it still refuses to show anything.
import UIKit
class DetailViewController: UIViewController {
var cards = [Card]()
#IBOutlet weak var cardsTableView: UITableView!
#IBOutlet weak var detailDescriptionLabel: UILabel!
var detailItem: AnyObject? {
didSet {
// Update the view.
self.configureView()
}
}
func configureView() {
// Update the user interface for the detail item.
if let detail: AnyObject = self.detailItem {
if let label = self.detailDescriptionLabel {
label.text = detail.description
}
}
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cards.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
//példányosítunk egy cellát
let cell = tableView.dequeueReusableCellWithIdentifier("CardCell", forIndexPath: indexPath) as CardCell
//kivesszük a sor adatait a listából
let card : Card = self.cards[indexPath.row]
cell.setCardNumber(card.number)
cell.layer.cornerRadius = 8
return cell
}
override func viewDidLoad() {
super.viewDidLoad()
self.cards = [Card(number: 123456789,type: 1)]
dispatch_async(dispatch_get_main_queue(), {
self.cardsTableView.reloadData()
})
self.configureView()
}
}
I started from a Master-Detail structure and I set the class of the Detail Scene to DetailViewController and the class and identifier of the Prototype to CardCell
class Card{
let number: Int
let type: Int
init(number: Int, type: Int){
self.number = number
self.type = type
}
}
import UIKit
class CardCell: UITableViewCell {
#IBOutlet weak var cardNumber: UILabel!
func setCardNumber(number: Int){
cardNumber.text = String(number)
}
}
I'm sure it's something basic, but I've been messing with this for the second day now. Any suggestions are appreciated.
you have to set the dataSource for the table view, i guess the delegate methods get never called.
Additionally add UITableViewDataSource, not necessary but more declarative than just the implementation
class DetailViewController: UIViewController, UITableViewDataSource {

Resources