Zhou Rui
Zhou Rui

Reputation: 55

App crashes randomly on viewWillDisappear()

I'm new to Swift, and I find some strange crashes in my app.

The Fabric reports said crashes occurred in viewWillDisappear().

I have two ViewControllers.User tap button in A viewcontroller then they move to B viewcontroller to input something, they user go back, and A get information from B.

I use a delegate to complete this task.

B:

class LessonNameTagTableViewController: UITableViewController {

...

var delegate:PassingData?

override func viewWillDisappear(_ animated: Bool) {

    lessonName = (tableView.cellForRow(at: IndexPath(row: 0, section: 0))?.viewWithTag(1) as! UITextField ).text!

    delegate?.changeLessonNameTag(name: lessonName, tag: tagColor)
    super.viewWillDisappear(animated)

}
...
}

A:

class LessonEditTableViewController: UITableViewController,PassingData {
var lesson :Lesson?
...
func changeLessonNameTag(name:String,tag:UIColor){
    self.lesson!.lessonName = name
    self.lesson!.lessonTagColor = tag
    tableView.reloadData()

}
...
}

The crash happened randomly, I've tested it on my device, and nothing happened.But others said they could repeat this crashes.

I wonder whether I'm using delegate right or it's caused by other reasons.

Upvotes: 0

Views: 830

Answers (3)

dmorrow
dmorrow

Reputation: 5694

If IndexPath{0,0} isn't visible when viewWillDisappear is called, then this line will set lessonName = nil as there is no cell for that row. That will cause the following line to crash.

lessonName = tableView.cellForRow(at: IndexPath(row: 0, section: 0))?.viewWithTag(1) as! UITextField ).text!

As others have mentioned, there are too many forced unwrappings.

However, unless that cell was dynamically populate by the user, you should be able to get the same value from your UITableViewDataSource - so it will work if the cell is visible or not.

Additionally, don't force unwrap lesson in your delegate method - could be nil.

func changeLessonNameTag(name:String,tag:UIColor){
    self.lesson?.lessonName = name
    self.lesson?.lessonTagColor = tag
    tableView.reloadData()
}

Upvotes: 1

Matthew Hallatt
Matthew Hallatt

Reputation: 1380

My gut reaction is that one of the object's you're force unwrapping is in fact nil.

Instead of force unwrapping it using the !, you should safely unwrap it and fail gracefully if it is not present:

func changeLesson(name: String, tag: UIColor) {    //Updated formatting and method declaration to fit with current Swift standards
    guard let lesson = lesson else {    //Don't need to reference self here
        return
    }

    lesson.lessonName = name
    lesson.lessonTagColor = tag

    tableView.reloadData()
}

See @orxelm's answer for how to safely unwrap your text value in B

Always be very wary when using the ! operator. Even if you think you can guarantee that the object will not ever be nil.

Upvotes: 0

orxelm
orxelm

Reputation: 1144

You probably have a problem in you viewWillDisappear, there's many optionals there that can cause you trouble when you force-unwrap.

It's better to be crash safe:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if let lessonName = (tableView.cellForRow(at: IndexPath(row: 0, section: 0))?.viewWithTag(1) as? UITextField)?.text {
        delegate?.changeLessonNameTag(name: lessonName, tag: tagColor)
    }
}

Upvotes: 1

Related Questions