UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

SOLVED: Milestone: Projects 19-21 - how to insert textView content in table view?

Forums > 100 Days of Swift

Hi everybody

How to insert text of textView in table view?

I would like to learn how to pass data from DetailViewController to ViewController ?

ViewController:

class ViewController: UITableViewController {

    var notes = [noteText]()

    // navigation items
    var editButton: UIBarButtonItem!
    var cancelButton: UIBarButtonItem!

    // toolbar items
    var spacerButton: UIBarButtonItem!
    var notesCountButton: UIBarButtonItem!
    var newNoteButton: UIBarButtonItem!

    override func viewDidLoad() {
        super.viewDidLoad()

        tableView.backgroundView = UIImageView(image: UIImage(named: "1x"))

        title = "Notes"
        navigationController?.navigationBar.prefersLargeTitles = true

        // navigation items
        editButton = UIBarButtonItem(barButtonSystemItem: .edit, target: self, action: #selector(editTapped))
        editButton.tintColor = .orange
        navigationItem.rightBarButtonItem = editButton

        // toolbar items
        newNoteButton = UIBarButtonItem(barButtonSystemItem: .compose, target: self, action: #selector(newNoteTapped))
        newNoteButton.tintColor = .orange
        spacerButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
        notesCountButton = UIBarButtonItem(title: "\(notes.count) Notes", style: .plain, target: nil, action: nil)
        notesCountButton.setTitleTextAttributes([
            NSAttributedString.Key.font : UIFont.systemFont(ofSize: 11),
            NSAttributedString.Key.foregroundColor : UIColor.darkText], for: .normal)
            toolbarItems = [spacerButton, notesCountButton, spacerButton, newNoteButton]
            navigationController?.isToolbarHidden = false
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        notes.count
    }
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let note = notes[indexPath.row]
        cell.textLabel?.text = note.name

        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if let vc = storyboard?.instantiateViewController(withIdentifier: "Details") as? DetailViewController {

            vc.noteDetail = notes[indexPath.row]   // Cannot assign value of type 'noteText' to type '[noteText]

         navigationController?.pushViewController(vc, animated: true)
        }
    }

    @objc func editTapped() {

    }

    @objc func newNoteTapped() {
        let storyboard = UIStoryboard(name: "Main", bundle: nil);
        let vc = storyboard.instantiateViewController(withIdentifier: "Details") as! DetailViewController
        self.navigationController?.pushViewController(vc, animated: true)
    }

}

DetailViewController:

class DetailViewController: UIViewController, UITextViewDelegate {
    @IBOutlet var textView: UITextView!

    var noteDetail: [noteText]!

    override func viewDidLoad() {
        super.viewDidLoad()

        let share = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(shareTapped))
        let done = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(doneTapped))
        // add multiple UIBarButtonItem to a navigation bar.
        navigationItem.rightBarButtonItems = [done, share]

        // for show keyboard and automatic scroll down during type.
        let notificationCenter = NotificationCenter.default
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)

        textView.textAlignment = .natural

    }

    @objc func shareTapped() {

        let shareText = textView.text ?? "No text Found"

        let vc = UIActivityViewController(activityItems: [shareText], applicationActivities: [])
        present(vc, animated: true)
    }

    @objc func doneTapped() {

    }
    // keyboard adjustment.
    @objc func adjustForKeyboard(notification: Notification) {
        guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }

        let keyboardScreenEndFrame = keyboardValue.cgRectValue
        let keyboardViewEndFrame = view.convert(keyboardScreenEndFrame, from: view.window)

        if notification.name == UIResponder.keyboardWillHideNotification {
            textView.contentInset = .zero

        } else {
            textView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardViewEndFrame.height, right: 0)
        }

        textView.scrollIndicatorInsets = textView.contentInset

        let selectedRange = textView.selectedRange
        textView.scrollRangeToVisible(selectedRange)
    }
}

noteText:

class noteText: Codable {
    var name: String

    init(name: String) {
        self.name = name
    }
}

3      

Hi @mahoozi97! I think you should better not to pass the data back to the mainview from detailview but save it instead. By that you will solve 2 issues, you don't have to pass it back but to read the data and you have your data saved in permanant storage so it will persist.

Back at the time when I tackling that challange I used the simple approach like below:

Created extension to FileManager

extension FileManager {
    static var documentsDirectory: URL {
        let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
        return paths[0]
    }
}

Created DataManager

struct DataManager {
    static let savePath = FileManager.documentsDirectory.appendingPathComponent("SavedNotes")

    static func load() -> [String] {
        if let data = try? Data(contentsOf: savePath) {
            if let decoded = try? JSONDecoder().decode([String].self, from: data) {
                return decoded
            }
        }
        print("no data to load")
        return []
    }

    static func save(_ notes: [String]) {
        if let data = try? JSONEncoder().encode(notes) {
            try? data.write(to: savePath, options: [.atomic, .completeFileProtection])
        }
    }
}

So after that you can use DataManager.save and DataManager.load where necessary.

And of course you will need to add this to your mainview, so whenever you have it back on your screen it will load all your notes from the file.

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

        readData()
        tableView.reloadData()
    }

3      

Hi @ygeras, how to use that ?

3      

In your detailview you will probably have textField for inserting text. Once you typed in your text, you will want to save it. So by using singleton DataManager.save(:) you can do it.

And when your view controller (main view) will appear you can retrieve your data from saved file again using singleton DataManager.load()

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

        notes = DataManager.load()
        tableView.reloadData()
    }

3      

Thank you @ygeras

3      

TAKE YOUR SKILLS TO THE NEXT LEVEL If you like Hacking with Swift, you'll love Hacking with Swift+ – it's my premium service where you can learn advanced Swift and SwiftUI, functional programming, algorithms, and more. Plus it comes with stacks of benefits, including monthly live streams, downloadable projects, a 20% discount on all books, and free gifts!

Find out more

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.