Swift Playgrounds 中的一个简单的笔记应用程序

A simple notes app in Swift Playgrounds

我正在尝试在 Swift Playgrounds 中创建一个简单的笔记应用程序,但我被卡住了。

如何在没有 prepareForSegue 的情况下将数据从主视图(即 UITableView)发送到详细视图(即 UITextView),反之亦然,因为没有故事板?

我错过了什么或做错了什么?

我一直在拼命寻找解决方案,因此非常感谢您的帮助。

这是我的游乐场:

import UIKit
import PlaygroundSupport

class MasterViewController: UITableViewController {

    var noteData: [String] = []
    var selectedRow: Int = -1
    var newRowLabel: String = ""

    override func viewDidLoad() {
        configureNavigationBar()
        loadNote()
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if selectedRow == -1 {
            return
        }
        noteData[selectedRow] = newRowLabel
        if newRowLabel == "" {
            noteData.remove(at: selectedRow)
        }
        tableView.reloadData()
        saveNote()
    }

    @objc func newNote() {
        let noteTitle: String = ""
        noteData.insert(noteTitle, at: 0)
        let indexPath: IndexPath = IndexPath(row: 0, section: 0)
        tableView.insertRows(at: [indexPath], with: .automatic)
        tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
        navigationController?.pushViewController(DetailViewController(), animated: true)
    }

    func configureNavigationBar() {
        title = "Notes"
        let addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(newNote))
        navigationItem.rightBarButtonItem = addButton
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return noteData.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "Cell")
        if cell == nil {
            cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")
        }
        cell?.textLabel?.text = noteData[indexPath.row]
        return cell!
    }

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        noteData.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: .fade)
        saveNote()
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        navigationController?.pushViewController(DetailViewController(), animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let detailView: DetailViewController = segue.destination as! DetailViewController
        selectedRow = tableView.indexPathForSelectedRow!.row
        detailView.masterView = self
        detailView.setText(noteText: noteData[selectedRow])
    }

    func saveNote() {
        UserDefaults.standard.set(noteData, forKey: "Notes")
        UserDefaults.standard.synchronize()
    }

    func loadNote() {
        if let loadedNote = UserDefaults.standard.value(forKey: "notes") as? [String] {
            noteData = loadedNote
            tableView.reloadData()
        }
    }
}

class DetailViewController: UIViewController {

    let textView = UITextView()
    var noteText: String = ""
    var masterView: MasterViewController!

    override func loadView() {
        configureDetailView()
    }

    override func viewDidLoad() {
        configureTextView()
    }

    func configureDetailView() {
        view = textView
    }

    func configureTextView() {
        textView.text = noteText
    }

    func setText(noteText: String) {
        if isViewLoaded {
            textView.text = noteText
        }
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        masterView?.newRowLabel = noteText
    }
}

let masterViewController = MasterViewController()
let navigationController = UINavigationController(rootViewController: masterViewController)

PlaygroundPage.current.liveView = navigationController

而不是

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    navigationController?.pushViewController(DetailViewController(), animated: true)
}

您可以像这样创建 DetailViewController 并分配 noteText

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let detailViewController = DetailViewController()
    detailViewController.noteText = noteData[indexPath.row]
    detailViewController.masterView = self
    navigationController?.pushViewController(detailViewController, animated: true)
}

函数prepare可以删掉,因为你没有用storyboards所以不用

别忘了适应 newNote():

@objc func newNote() {
    let noteTitle: String = ""
    noteData.insert(noteTitle, at: 0)
    let indexPath: IndexPath = IndexPath(row: 0, section: 0)
    tableView.insertRows(at: [indexPath], with: .automatic)
    tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
    let detailViewController = DetailViewController()
    detailViewController.masterView = self
    navigationController?.pushViewController(detailViewController, animated: true)
}

在您的 didSelectRow 方法中:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    navigationController?.pushViewController(DetailViewController(), animated: true)
}

你正在创建你的 DetailViewController() 但当你的视图控制器有变量来接受数据时没有向它传递任何数据,所以为了做到这一点而不是做:

navigationController?.pushViewController(DetailViewController(), animated: true)

你可以做到:

let detailVC = DetailViewController()
    detailVC.noteText = noteData[indexPath.row]
    navigationController?.pushViewController(detailVC, animated: true)

编辑: 我正在从这里更新我的答案,因为您的解决方案需要进行大量更改才能实现,就像我上面解释的如何传递数据的方式一样,您有在不同的地方以及您创建新笔记的地方执行此操作

首先,为了让您的新内容保存并让 table 视图单元格自行更新,您需要调整您的 newNote() 功能:

@objc func newNote() {
    let noteTitle: String = ""
    noteData.insert(noteTitle, at: 0)
    let indexPath: IndexPath = IndexPath(row: 0, section: 0)
    tableView.insertRows(at: [indexPath], with: .automatic)
    tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
    selectedRow = indexPath.row
    let detailVC = DetailViewController()
    detailVC.masterView = self
    navigationController?.pushViewController(detailVC, animated: true)
}

您将 selectedRow 变量设置为插入的 indexPath 并将 masterView 传递给 DetailsViewController()

其次,您还需要更改 didSelectRow,使用我发布的相同解决方案,但同样也将您的 masterViewselectedRow 也传递到那里,所以它应该看起来像这样:

let detailVC = DetailViewController()
    detailVC.noteText = noteData[indexPath.row]
    detailVC.masterView = self
    selectedRow = indexPath.row
    navigationController?.pushViewController(detailVC, animated: true)

第三,您的 DetailViewController 缺少一件事,无论何时在您的文本视图中输入文本,它都不会更新 noteText 而您的 viewWillDisappear 方法依赖于此,您需要设置文本视图的委托自己听文本变化,但是为了更简单的解决方案,将您的 viewWillDisappear 更改为直接访问 textView,如下所示:

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    masterView?.newRowLabel = textView.text
}

第四,当你从这个屏幕返回时,你的 MasterViewController 需要将它保存在你的 viewWillAppear 方法中,那里也需要一些改变,实际上并不多,你只需要重置你的 selectedRow 保存注释后变量,因此在您调用后:

saveNote()

在下一行还添加:

selectedRow = -1