Chetan Lodhi
Chetan Lodhi

Reputation: 353

How to update UITableviewcell label in other method in swift3?

I am trying to update a UITableviewcell's label in other method. I also saw many post on stackoverflow, non was work for me. i am using Swift 3 and I tried this one :

    let indexPath = IndexPath.init(row: 0, section: 0)
    let cell : CategoryRow = tableView.cellForRow(at: indexPath) as! CategoryRow

and i am getting this error :

fatal error: unexpectedly found nil while unwrapping an Optional value

i am using this in other method where i update tableviewcell label text after 24hr. code is here

var myQuoteArray = ["“If you have time to breathe you have time to meditate. You breathe when you walk. You breathe when you stand. You breathe when you lie down. – Ajahn Amaro”","We are what we repeatedly do. Excellence, therefore, is not an act but a habit. – Aristotle","The best way out is always through. – Robert Frost","“If you have time to breathe you have time to meditate. You breathe when you walk. You breathe when you stand. You breathe when you lie down. – Ajahn Amaro”","We are what we repeatedly do. Excellence, therefore, is not an act but a habit. – Aristotle","The best way out is always through. – Robert Frost"

    ]
func checkLastRetrieval(){

   //        let indexPath = IndexPath.init(row: 0, section: 0)
   //        let cell : CategoryRow = tableView.cellForRow(at: indexPath) as? CategoryRow


    let indexPath = IndexPath.init(row: 0, section: 0)
   guard let cell = tableView.cellForRow(at: indexPath) as? CategoryRow else { return }

    print("Getting Error line 320")// This is not printing on console

let userDefaults = UserDefaults.standard

if let lastRetrieval = userDefaults.dictionary(forKey: "lastRetrieval") {
if let lastDate = lastRetrieval["date"] as? NSDate {
if let index = lastRetrieval["index"] as? Int {
if abs(lastDate.timeIntervalSinceNow) > 86400 { // seconds in 24 hours
// Time to change the label
var nextIndex = index + 1

// Check to see if next incremented index is out of bounds
if self.myQuoteArray.count <= nextIndex {
// Move index back to zero? Behavior up to you...
nextIndex = 0
}



cell?.quotationLabel.text = self.myQuoteArray[nextIndex]

let lastRetrieval : [NSObject : AnyObject] = [
"date" as NSObject : NSDate(),
"index" as NSObject : nextIndex as AnyObject
]

userDefaults.set(lastRetrieval, forKey: "lastRetrieval")
userDefaults.synchronize()
}
// Do nothing, not enough time has elapsed to change labels
}
}
} else {

// No dictionary found, show first quote
cell?.quotationLabel.text = self.myQuoteArray.first!

     print("line 357")
// Make new dictionary and save to NSUserDefaults
let lastRetrieval : [NSObject : AnyObject] = [
"date" as NSObject : NSDate(),
"index" as NSObject : 0 as AnyObject
]

userDefaults.set(lastRetrieval, forKey: "lastRetrieval")
userDefaults.synchronize()
}

}

and Calling this method in ViewDidLoad()

 override func viewDidLoad() {
    super.viewDidLoad()

     checkLastRetrieval()
    }

what should i do? Thanks in Advance

Upvotes: 0

Views: 96

Answers (2)

Paulw11
Paulw11

Reputation: 114865

The function cellForRow(at:) returns nil if the requested cell is not currently onscreen. Since you are calling your function in viewDidLoad there will be no cells on screen. This results in the crash because you have force downcast the result of cellForRow(at:).

You should never use a force unwrap or a force downcast unless you are absolutely certain the result cannot be nil and/or the only possible action if it is nil is for your app to crash.

Generally you should not update cells directly. It is better to update the table's data model and then call reloadRows(at:,with:) and let your data source cellForRow(at:) function handle updating the cell.

If you are going to update the cell directly then make sure you use a conditional downcast with if let or guard let to avoid a crash if the cell isn't visible. In this case you still need to update your data model so that the cell data is correct when the cell does come on screen.

Upvotes: 1

Vlad Khambir
Vlad Khambir

Reputation: 4383

You should use guard let statement:

let indexPath = IndexPath(row: 0, section: 0)
guard let cell = tableView.cellForRow(at: indexPath) as? CategoryRow else { return }

If your cell type is not CategoryRow, you will return from the method. Try to find out why is your cell type not a CategoryRow.

Upvotes: 0

Related Questions