I've been racking my mind for days trying to figure this out. I have two view controllers (WorkoutViewController and WorkoutAlertViewController). The WorkoutViewController is a tableView for all workouts created. It has swipe action for edit / delete. This view controller also has a "+" as a bar button to open the WorkoutAlertViewController. Also, on the swipe action edit, the WorkoutAlertViewController opens.
The WorkoutAlertViewController takes the input from the user and passes the data back to the WorkoutViewController upon pressing the Add button.
Here is the issue. I have a protocol / delegate that gets the user's input entered into WorkoutAlertViewController and passes the information back to the WorkoutViewController to populate the tableView. This works great, However, when the user wants to edit a workout. I need that workout's information to populate the entries on the WorkoutAlertViewController, No matter what I've tried. the delegate for this protocol always returns nil, Therefore. no data is passed.
Here is necessary code for WorkoutViewController:
protocol PassExistingWorkout {
func didTapEdit(workout: Workout)
}
class WorkoutViewController: UIViewController {
var workoutDelegate: PassExistingWorkout!
@IBAction func addButtonPressed(_ sender: UIBarButtonItem) {
let alertVC = storyboard!.instantiateViewController(withIdentifier: "WorkoutVC") as! WorkoutAlertViewController
alertVC.alertDelegate = self
present(alertVC, animated: true, completion: nil)
}
}
extension WorkoutViewController: PassNewWorkout {
func didTapAdd(name: String, time: String, date: Date) {
workoutName = name
averageTime = time
creationDate = date
let newWorkout = Workout()
newWorkout.name = workoutName
newWorkout.dateCreated = creationDate
newWorkout.time = averageTime
saveWorkout(workout: newWorkout)
}
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "Delete") { (action, view, actionPerformed) in
if let _ = tableView.cellForRow(at: indexPath){
do {
try self.realm.write {
self.realm.delete(self.workoutItems![indexPath.row])
}
} catch {
print("Error saving category \(error)")
}
}
tableView.reloadData()
}
deleteAction.backgroundColor = .red
let editAction = UIContextualAction(style: .normal, title: "Edit") { (action, view, actionPerformed) in
let alertVC = self.storyboard!.instantiateViewController(identifier: "WorkoutVC") as! WorkoutAlertViewController
self.present(alertVC, animated: true, completion: nil)
if let _ = tableView.cellForRow(at: indexPath){
self.passedWorkout = self.workoutItems![indexPath.row]
self.workoutDelegate.didTapEdit(workout: self.passedWorkout)
}
}
editAction.backgroundColor = .gray
return UISwipeActionsConfiguration(actions: [deleteAction, editAction])
}
}
Here is the code for WorkoutAlertViewController:
protocol PassNewWorkout {
func didTapAdd(name: String, time: String, date: Date)
}
class WorkoutAlertViewController: UIViewController {
var alertDelegate: PassNewWorkout!
@IBAction func addButtonPressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
workoutName = workoutTextField.text!
creationDate = datePicker.date
averageTime = timeTextField.text!
alertDelegate.didTapAdd(name: workoutName, time: averageTime, date: creationDate)
}
override func viewDidLoad() {
super.viewDidLoad()
let workoutVC = storyboard!.instantiateViewController(identifier: "Main") as! WorkoutViewController
workoutVC.workoutDelegate = self
}
extension WorkoutAlertViewController: PassExistingWorkout {
func didTapEdit(workout: Workout) {
receivedWorkout = workout
}
}
The app crashes in the editAction when calling:
self.workoutDelegate.didTapEdit(workout: self.passedWorkout)
Error: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value: file. As far as I can figure out, the workoutDelegate is not created (nil).
As always, any guidance is greatly appreciated.
You dont need delegate for forward communication.. you can simply call that function directly
let editAction = UIContextualAction(style: .normal, title: "Edit") { (action, view, actionPerformed) in
let alertVC = self.storyboard!.instantiateViewController(identifier: "WorkoutVC") as! WorkoutAlertViewController
self.passedWorkout = self.workoutItems![indexPath.row]
alertVC.didTapEdit(workout: self.passedWorkout)
self.present(alertVC, animated: true, completion: nil)
}
In you other class do
class WorkoutAlertViewController: UIViewController {
var alertDelegate: PassNewWorkout!
@IBAction func addButtonPressed(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
workoutName = workoutTextField.text!
creationDate = datePicker.date
averageTime = timeTextField.text!
alertDelegate.didTapAdd(name: workoutName, time: averageTime, date: creationDate)
}
override func viewDidLoad() {
super.viewDidLoad()
}
func didTapEdit(workout: Workout) {
receivedWorkout = workout
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.