Swift Playgrounds 中的简单笔记应用

Posted

技术标签:

【中文标题】Swift Playgrounds 中的简单笔记应用【英文标题】:A simple notes app in Swift Playgrounds 【发布时间】:2017-10-28 07:14:57 【问题描述】:

我正在尝试在 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

【问题讨论】:

【参考方案1】:

在您的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)

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

首先要保存新的表格视图单元格并自行更新,您需要将 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 方法依赖于此,您需要将文本视图的委托设置为 self 并收听文本更改,但是为了更简单的解决方案,将您的viewWillDisappear 更改为直接访问textView,如下所示:

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

第四,当您从该屏幕返回时,您的 MasterViewController 需要将其保存在您的 viewWillAppear 方法中,那里也需要进行一些更改,实际上您只需要重置您的 selectedRow 变量即可打电话后保存:

saveNote()

在下一行还添加:

selectedRow = -1

【讨论】:

@BoleTzar 我刚刚更新了我的答案,指出了代码中需要解决的问题【参考方案2】:

代替

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可以删除,因为你不用storyboard所以没用。

别忘了适应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)

【讨论】:

我删除了prepare 函数并添加了您建议的代码,但在UITextView 中输入的文本没有保存,表格单元格仍然没有更新。有什么想法吗? 我将detailViewController.masterView = self 添加到didSelectRowAt...。而且你必须调整newNote函数来设置masterView

以上是关于Swift Playgrounds 中的简单笔记应用的主要内容,如果未能解决你的问题,请参考以下文章

Swift Playgrounds 可以查看同一个项目中的其他源文件吗?

Swift Playgrounds 中的 JavaScriptCore

Swift Playgrounds 中的 UIGestureRecognizer

Swift Playgrounds 中的视图数量有限

如何将视频保存到 Swift Playgrounds 中的 URL

如何解决 Swift Playgrounds 中的“运行此页面时出现问题”消息?