How to reload a collectionview when I tap on back? - swift

My collectionview did not reload when I tap back from the tableview where I the list reorder.
I have read a few topics but I don't know what's wrong. Can anybody find it?
And can I the speak part of the code place in an apart swift file and include this ViewController. So yes, how? Because I use that in more ViewControllers.
Below is my code.
Thank you very much.
import UIKit
import AVFoundation
class CollectionViewController: UICollectionViewController {
#IBOutlet var soundBoard: UICollectionView!
var list = ["January","February","March","April","May","June", "July","August","September","October","November", "December"]
var bgColor = [""]
var buttonOn: Bool = true
override func viewDidLoad() {
super.viewDidLoad()
let blockItems = UserDefaults.standard.object(forKey:"soundboard")
if(blockItems != nil) {
list = blockItems as! [String]
}
let itemSize = UIScreen.main.bounds.width/2 - 2
let itemHeight = itemSize / 2
let layout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsetsMake(3, 0, 3, 0)
layout.itemSize = CGSize(width: itemSize, height: itemHeight)
layout.minimumInteritemSpacing = 3
layout.minimumLineSpacing = 3
soundBoard.collectionViewLayout = layout
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.collectionView!.reloadData()
}
// MARK: - Collection View
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of items
return list.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> MyCollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyCollectionViewCell
cell.cellTitle.text = list[indexPath.row]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
Speak(currentTitle: list[indexPath.row])
}
// MARK: - Speak function
let synth = AVSpeechSynthesizer()
var myUtterance = AVSpeechUtterance(string: "")
func Speak(currentTitle: String) {
if !synth.isSpeaking {
// Controleert volume
let volume = AVAudioSession.sharedInstance().outputVolume
if volume < 0.5 {
MuteButton()
}
// Spreekt de tekst uit
let myUtterance = AVSpeechUtterance(string: currentTitle)
myUtterance.rate = 0.4
myUtterance.volume = 1
if let theVoice = UserDefaults.standard.object(forKey:"voice") {
myUtterance.voice = AVSpeechSynthesisVoice(language: theVoice as? String)
}
synth.speak(myUtterance)
}
}
func MuteButton() {
let alertController = UIAlertController(title: "Check your volume", message:
"Please check your volume or mute button.", preferredStyle: UIAlertControllerStyle.alert)
alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: -- Save UserDefaults
func save() {
UserDefaults.standard.set(self.list, forKey:"soundboard")
UserDefaults.standard.synchronize()
self.collectionView?.reloadData()
}
// MARK: -- Add new sound item
#IBAction func addNew(_ sender: Any) {
let alertController = UIAlertController(title: "Create a new sound", message: "", preferredStyle: UIAlertControllerStyle.alert)
alertController.addTextField { (textField: UITextField) in
textField.keyboardAppearance = .dark
textField.keyboardType = .default
textField.autocorrectionType = .default
textField.placeholder = "Type something here"
textField.clearButtonMode = .whileEditing
}
alertController.addAction(UIAlertAction(title: "Create", style: .default) { [weak alertController] _ in
if let alertController = alertController {
let loginTextField = alertController.textFields![0] as UITextField
self.list.append( loginTextField.text!)
self.save()
}
})
alertController.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default,handler: nil))
self.present(alertController, animated: true, completion: nil)
}
}

Two things are happening here. First you appear to have two different collection views in CollectionViewController; collectionView which is inherited from the superclass and soundboard which you declare. In viewWillAppear you tell collectionView to reload. If this is not the one that is hooked up in IB nothing will work.
The second issue is that while in soundboardTableViewController you update the user default with the correct data you never read it after the view loads in CollectionViewController.
You should move this:
let blockItems = UserDefaults.standard.object(forKey:"soundboard")
if(blockItems != nil) {
list = blockItems as! [String]
}
into viewWillAppear before your call to reload the collection view and then verify you are telling the right collection view to reload.

I see a few things that could be going wrong here. It would help to see the code in the other view controller however.
First are you sure that you're reordering your model array properly? Remember in swift an array is a value type. Meaning that if you pass the array to another view you're passing a copy of that array and not the array in your collection view controller. It may be a better idea to wrap your model array in an object which you can pass a reference to. More on that here.
Also it's better to tie a reload to a change in your model instead of the view lifecycle. To do that with your current code you could do something like this:
var list = ["January","February","March","April","May","June", "July","August","September","October","November", "December"] {
didSet {
self.collectionView?.reloadData()
// or
self.soundBoard.reloadData()
// I'm confused about which collection view you're using/trying to reload.
}
}
Please let me know if you have any questions. I'll keep an eye out and can edit my answer if needed.

This is the code of the other ViewController where you can reorder the rows and can tap on < Back.
import UIKit
class soundboardTableViewController: UITableViewController {
var list = ["January","February","March","April","May","June", "July","August","September","October","November", "December"]
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.rightBarButtonItem = self.editButtonItem
let blockItems = UserDefaults.standard.object(forKey:"soundboard")
if(blockItems != nil) {
list = blockItems as! [String]
}
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return list.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = list[indexPath.row]
return cell
}
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
/* Override to support editing the table view.*/
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
list.remove(at: indexPath.row)
UserDefaults.standard.set(self.list, forKey:"soundboard")
UserDefaults.standard.synchronize()
tableView.reloadData()
}
}
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt indexPath: IndexPath, to: IndexPath) {
/*let itemToMove = list[indexPath.row]
list.remove(at: indexPath.row)
list.insert(itemToMove, at: indexPath.row)
UserDefaults.standard.set(self.list, forKey:"soundboard")
UserDefaults.standard.synchronize()*/
let itemToMove = list[indexPath.row]
list.remove(at: indexPath.row)
list.insert(itemToMove, at: to.row)
UserDefaults.standard.set(self.list, forKey:"soundboard")
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
if(self.isEditing) {
}
}
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
}

Related

UITableView Not Showing Reorder Controls

When I use trailingSwipeActionsConfigurationForRowAt my TableView will show the delete and reorder options, however when selecting reorder nothing happens. I think I have all of the correct methods and am calling setEditing; is there anything else I'm missing? Thanks!
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
setupTableView()
}
func setupTableView() {
tableView.frame = self.view.frame
tableView.dataSource = self
tableView.delegate = self
tableView.register(CustomCell.self, forCellReuseIdentifier: "CustomCell")
tableView.dragInteractionEnabled = true
self.view.addSubview(tableView)
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 8
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.backgroundColor = .gray
cell.showsReorderControl = true
return cell
}
override func setEditing(_ editing: Bool, animated: Bool) {
super.setEditing(editing, animated: animated)
self.tableView.setEditing(editing, animated: animated)
}
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .normal, title: "delete") { (action, view, completion) in
tableView.reloadData()
completion(true)
}
let reorderAction = UIContextualAction(style: .normal, title: "reorder") { (action, view, completion) in
tableView.setEditing(true, animated: true)
completion(true)
}
return UISwipeActionsConfiguration(actions: [deleteAction, reorderAction])
}
}
class CustomCell: UITableViewCell {
}
Result after swiping:
After selecting reorder:
A few observations:
You are not going to get the reorder controls if you do not implement tableView(_:moveRowAt:to:), e.g., assuming you had a model which was an array called objects, you could do the following:
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let object = objects.remove(at: sourceIndexPath.row)
objects.insert(object, at: destinationIndexPath.row)
}
The trailingSwipeActionsConfigurationForRowAt is probably not the right place to put a “reorder” command. Part of the reason is that once the table view is in edit mode and you tap on the ⛔️, the trailing actions show up, and “reorder” does not make sense in that context. E.g., here I am tapping on ⛔️ and I see the confusing actions.
I would suggest only adding “delete” as the trailing action. That way, you (a) get only “delete” if you tap on ⛔️ in isEditing mode, but also (b) get the stand-alone swipe action, too.
You cannot initiate isEditing from the trailing swipe actions (and, as discussed above, I do not think you want to, anyway). So, if you do not have “reorder” in the trailing swipe actions, you need some other method to enter edit mode. E.g., above, I added an “edit” button to the navigation bar that toggles isEditing:
#IBAction func didTapEdit(_ sender: Any) {
tableView.isEditing.toggle()
}
Then, you can keep the swipe to delete functionality, but when you tap on edit button, you have the tap on ⛔️ to delete functionality (plus the handles for reordering because we added tableView(_:moveRowAt:to:) as outlined in step one, above):
Another way to achieve reordering is to just allow drag and drop within the table view where you can long-press on a row and then drag it:
This is enabled by setting dragInteractionEnabled and dropDelegate:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
let formatter: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
return formatter
}()
private var objects: [Foo] = ...
override func viewDidLoad() {
super.viewDidLoad()
...
tableView.dragInteractionEnabled = true
tableView.dropDelegate = self
}
}
// MARK: - UITableViewDataSource
extension ViewController: UITableViewDataSource { ... }
// MARK: - UITableViewDelegate
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
let deleteAction = UIContextualAction(style: .destructive, title: "delete") { [weak self] action, view, completion in
self?.objects.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .middle)
completion(true)
}
return UISwipeActionsConfiguration(actions: [deleteAction])
}
// This is used if table view is in `isEditing` mode and by `UITableViewDropDelegate`
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let object = objects.remove(at: sourceIndexPath.row)
objects.insert(object, at: destinationIndexPath.row)
}
}
// MARK: - UITableViewDropDelegate
extension ViewController: UITableViewDropDelegate {
func tableView(_ tableView: UITableView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UITableViewDropProposal {
guard
session.items.count == 1, // Accept only one drag item ...
tableView.hasActiveDrag // ... from within this table view
else {
return UITableViewDropProposal(operation: .cancel)
}
return UITableViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
}
func tableView(_ tableView: UITableView, performDropWith coordinator: UITableViewDropCoordinator) {
guard let destinationIndexPath = coordinator.destinationIndexPath else { return }
for item in coordinator.items {
if let sourceIndexPath = item.sourceIndexPath {
DispatchQueue.main.async {
tableView.moveRow(at: sourceIndexPath, to: destinationIndexPath)
}
}
}
}
}
Clearly, if you were going to enable drag from this app to others, you would add UITableViewDragDelegate conformance here, and make your model objects conform to NSItemProviderReading and NSItemProviderWriting. But the above should be sufficient for dragging and dropping to reorder within a UITableView.

How to Create A Tableview in Swift In Which Every Cell Pushes To New Table View

I Am New To Swift And App Development. I need To Create A Tableview In Which Every Cell Creates New Unique Tableview. Any Body Who Have An Idea Of How It Gets Done Please Help This Is My Code
class TableViewController1: UIViewController, UITableViewDataSource, UITableViewDelegate{
#IBOutlet weak var tblView: UITableView!
var datasourceArray = [Person]()
let appDelegete = UIApplication.shared.delegate as! AppDelegate
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
fetchAndUpdateTable()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let person = datasourceArray[indexPath.row]
appDelegete.deleteRecord(person: person)
fetchAndUpdateTable()
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row % 2 == 0{
let altCellColor: UIColor? = UIColor(white: 0.7, alpha: 0.5)
cell.backgroundColor = altCellColor
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return datasourceArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
let person = datasourceArray[indexPath.row]
cell?.textLabel?.text = person.steppiename! + " -- " + person.steppiedescription!
return cell!
}
func fetchAndUpdateTable(){
datasourceArray = appDelegete.fetchRecords()
tblView.reloadData()
}
#IBAction func addRecord(_ sender: UIButton) {
var steppienameTextField: UITextField?
var steppiedescriptionTextField: UITextField?
//Declare Alert Message
let dialogMessage = UIAlertController(title: "New Steppie", message: "Please Provide Steppie Name And Decsription", preferredStyle: .alert)
//Create Ok Button With Action Handler
let ok = UIAlertAction(title : "OK", style: .default, handler:
{
(action) -> Void in
let steppiename = steppienameTextField?.text
let steppiedescription = steppiedescriptionTextField?.text
if steppiename != nil && steppiedescription != nil{
self.appDelegete.insertRecord(steppiename: steppiename!, steppiedescription: steppiedescription!)
self.fetchAndUpdateTable()
}
})
//Create Cancel Button With Action handler
let cancel = UIAlertAction(title: "Cancel", style: .cancel)
{ (action) -> Void in
print("Cancel Button Tapped")
}
//Add OK and Cancel Button To Dialog Message
dialogMessage.addAction(ok)
dialogMessage.addAction(cancel)
//Add Input TextField To Dialog Message
dialogMessage.addTextField { (textField) -> Void in
steppienameTextField = textField
steppienameTextField?.placeholder = "Steppie Name"
}
dialogMessage.addTextField { (textField) -> Void in
steppiedescriptionTextField = textField
steppiedescriptionTextField?.placeholder = "Steppie Description"
}
//present Dialog message To User
self.present(dialogMessage,animated: true,completion: nil)
}
#IBAction func backButton(_ sender: UIButton) {
dismiss(animated: true, completion: nil)
}
}
You have two solutions here.
You can implement a method of UITableViewDelegate func tableView(UITableView, didSelectRowAt: IndexPath) and navigate to another ViewController with table view.
You can change your current data source after tap on cell. Don't forget to reload your table view after that tableView.reloadData(). If you will show something else (not a person) you can create enum for that.
enum Data {
case person(Person)
case other(Other)
}

How do I inject or add data to my table as it isn't working?

I just cannot seem to update data in Swift! I am trying to build a radio player app for a friends radio station so when a song changes I need to update the playlist viewcontroller.
The data from my Main View Controler is a instance of a struct. I know there is data being generated and it is passed to the table but for whatever reason the array isn't updating. I am sure it is something simple.
I have tried directly injecting the data with a call, using a protocol and using a function. Using the protocol and function I can see the passed data via print statement.
class PlaylistVC: UIViewController, UITableViewDelegate, UITableViewDataSource {
//Mark: Variables ~~~~~~~~~~~~###########################################
var sourceDatas = [PlaylistData]()
//Mark: View Containers ~~~~~############################################
private let bg = GradientBG()
private let closeButton = UIButton()
let playlistTable = UITableView()
//Mark: Overrides ~~~~~~~~~~~~###########################################
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
playlistTable.delegate = self
playlistTable.dataSource = self
layoutUI()
setupTable()
setupClose()
}
//Mark: objc func's ~~~~~~~~~~~###########################################
#IBAction func handleXButton() {
dismiss(animated: true, completion: nil)
}
func handleMoreInfo(_ playlist: PlaylistData) {
let vc = SongPopUp()
vc.buildLables(playlist)
vc.modalPresentationStyle = .overCurrentContext
self.present(vc, animated: true, completion: nil )
}
//##################################################################
//Mark: Pass Data ##################################################
//Mark: Not Working!! ##############################################
//##################################################################
func handlePlaylist(_ with: PlaylistData) {
print(with)
sourceDatas.append(with)
//sourceDatas.insert(with, at: 0)
playlistTable.reloadData()
}
//Mark: Table view ################################################
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sourceDatas.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:UITableViewCell = UITableViewCell(style: .subtitle, reuseIdentifier: "myCell")
cell.backgroundColor = .clear
cell.selectionStyle = .none
tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath)
if let text = cell.textLabel {
components.layoutHeadingLable(sender: text, title: sourceDatas[indexPath.row].heading, size: 20)
}
if let dtext = cell.detailTextLabel {
components.layoutSubheadingLable(sender: dtext, title: sourceDatas[indexPath.row].subheading, size: 14)
}
if sourceDatas[indexPath.item].hasStoreLink {
cell.accessoryType = .detailButton
cell.tintColor = .white
}
return cell
}
func tableView(_ tableView: UITableView, accessoryButtonTappedForRowWith indexPath: IndexPath) {
let dataToPass = self.sourceDatas[indexPath.row]
print("Extended~~~~~~~~~~~~~~~~~~~~")
print(dataToPass)
handleMoreInfo(sourceDatas[indexPath.row])
}
//Mark: Setup Table ~~~~~~~~~~~~~~###########################################
func setupTable() {
playlistTable.backgroundColor = .clear
playlistTable.separatorStyle = .singleLine
playlistTable.rowHeight = 45
playlistTable.register(UITableViewCell.self, forCellReuseIdentifier: "myCell")
}
......
I think it's something wrong with your cellForRowAt
Try to make it simple first, like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! UITableViewCell
cell.textLabel?.text = sourceDatas[indexPath.row]
return cell
}
See whether you can find the added object. Then dive into the detail settings of your cell.

Not able to add items to list with Core Data

When I press Add no item gets added to the list. What is wrong with my code?
I am trying to make a grocery list with persistence using Core Data.
Please help me.
Is it a mistake in the Core Data part or with the alertController?
import UIKit
import CoreData
class GroceryTableTableViewController: UITableViewController {
var groceries = [NSManagedObject]()
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
}
override func viewWillAppear(_ animated: Bool) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
super.viewWillAppear(animated)
loadData()
}
func loadData(){
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let request:NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Groceries")
do {
let results = try managedContext.fetch(request)
groceries = results as! [NSManagedObject]
}
catch {
//print(<#T##items: Any...##Any#>)("Error in retrieving Grocery items")
let fetchError = error as NSError
print(fetchError)
}
}
#IBAction func addAction(_ sender: UIBarButtonItem) {
let alertController = UIAlertController(title: "Grocery List", message: "Add Item", preferredStyle: UIAlertControllerStyle.alert)
alertController.addTextField { (textField : UITextField!) -> Void in
}
let addAction = UIAlertAction(title: "Add", style:UIAlertActionStyle.default) { (action: UIAlertAction) -> Void in
func saveItem(itemToSave : String) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let managedContext = appDelegate.persistentContainer.viewContext
let entityDescription = NSEntityDescription.entity(forEntityName: "Groceries", in: managedContext)
let item = NSManagedObject(entity: entityDescription!, insertInto: managedContext)
item.setValue(itemToSave, forKey: "item")
do {
try managedContext.save()
self.groceries.append(item)
}
catch {
print("Error in storing to Core Data")
}
}
self.loadData()
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.default) { (action: UIAlertAction) -> Void in
}
alertController.addAction(addAction)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return groceries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
let item = groceries[indexPath.row]
cell.textLabel?.text = item.value(forKey: "item") as! String
return cell
}
/*
// Override to support conditional editing of the table view.
override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the specified item to be editable.
return true
}
*/
/*
// Override to support editing the table view.
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
// Delete the row from the data source
tableView.deleteRows(at: [indexPath], with: .fade)
} else if editingStyle == .insert {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
*/
/*
// Override to support rearranging the table view.
override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {
}
*/
/*
// Override to support conditional rearranging of the table view.
override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
// Return false if you do not want the item to be re-orderable.
return true
}
*/
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}

Second segue from TableViewController creating SIGABRT error relating to the first

I have created a NoteBook application within a larger app. I have all the functionality working including a segue to an Add Note page which triggers programatically from clicking a note (to edit it) or a + barButtonItem.
I need a second segue to send the user back to the home page of the app, but every way I seem to try it conflicts with the existing segue I have in place.
Can anyone suggest a way to get the second segue to work. They both have different identifiers which I am referencing in the methods. Its just the goHome segue that will not work...
class NoteBookViewController: UITableViewController, NoteViewDelegate {
func didUpdateNoteWithTitle(newTitle: String, andBody newBody: String) {
self.noteBookEntries[self.selectedIndex] ["title"] = newTitle
self.noteBookEntries[self.selectedIndex] ["body"] = newBody
self.tableView.reloadData()
saveNotesArray()
}
var noteBookEntries = [[String:String]] ()
#IBAction func newNote() {
var newNote = ["title" : "", "body" : ""]
noteBookEntries.insert(newNote, at: 0)
self.selectedIndex = 0
self.tableView.reloadData()
saveNotesArray()
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
var selectedIndex = -1
func saveNotesArray() {
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
UserDefaults.standard.synchronize()
}
override func viewDidLoad() {
super.viewDidLoad()
if let newNote = UserDefaults.standard.array(forKey: "notes") as? [[String:String]] {
noteBookEntries = newNote
}
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.reply, target: self, action: #selector(NoteBookViewController.navigateToNextViewController))
}
func navigateToNextViewController(){
self.performSegue(withIdentifier: "goHome", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return noteBookEntries.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell (withIdentifier: "CELL")! as UITableViewCell
cell.textLabel?.text = noteBookEntries[indexPath.row]["title"]
return cell
}
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == UITableViewCellEditingStyle.delete {
noteBookEntries.remove(at: indexPath.row)
UserDefaults.standard.set(noteBookEntries, forKey: "notes")
self.tableView.reloadData()
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.selectedIndex = indexPath.row
performSegue(withIdentifier: "editNoteBookSegue", sender: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?) {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
notesEditorVC.navigationItem.title = noteBookEntries[self.selectedIndex] ["title"]
notesEditorVC.noteBodyText = noteBookEntries[self.selectedIndex] ["body"]
notesEditorVC.delegate = self
}
}
error message relating to original segue - this segue works until the second is added
In your prepareForSegue method first line is:
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
This method is called for each of your segues. When it is called for your first segue it works totally fine because the destination view controller is, in fact, of type NewNoteBookEntryViewController.
However, when this method is called for your second segue, the destination controller is of different type. So, you get a crash when you force downcast it.
You should add some logic to your prepareForSegue method so that you distinguish between segues. For example:
if segue.identifier == "addNote" {
let notesEditorVC = segue.destination as! NewNoteBookEntryViewController
//some other code
}
Solved by adding the logic and then adding this to the destination controller:
override func viewWillAppear(animated: Bool) {
self.navigationController?.setNavigationBarHidden(true, animated: true)
}