Day#08 查看、删除

前言

今天的内容有些跟前几天的类似,就当作是刻意练习吧。

EntryViewController

进入新的页面之後,帮昨天做好的元件新增一些功能。

viewDidLoad

datePicker.setDate(Date(), animated: true) // today

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Save", style: .done, target: self, action: #selector(didTapSaveButton))

首先加上datePicker的初始值(当下),然後加上储存的按钮。当按下的时候会触发didTapSaveButton

didTapSaveButton

按下按钮的时候,尝试对DB进行写入一笔新的transaction,其中的资料就是刚刚输入的结果。
Factory for a write Transaction. Essential object to create scope for updates.

@objc func didTapSaveButton() {
    if let text = textField.text, !text.isEmpty {
        let date = datePicker.date

        realm.beginWrite()

        let newItem = TodoListItem()
        newItem.date = date
        newItem.item = text
        realm.add(newItem)

        try! realm.commitWrite()

        completionHandler?()
        navigationController?.popToRootViewController(animated: true)

    } else {
        print("add something")
    }
}

昨天好像没有对hanlder做足够的描述,至少我自己还是一知半解。

Why Completion Handlers

`
Before we dive into a technical aspect, let’s talk about what it means to use completion handlers. Assume the user is updating an app while using it. You definitely want to notify the user when it is done. You possibly want to pop up a box that says,“Congratulations, now, you may fully enjoy!”

So, how do you run a block of code only after the download has been completed? Further, how do you animate certain objects only after a view controller has been moved to the next? Well, we are going to find out how to design one like a boss.

Based on my expansive vocabulary list, completion handlers stand for,
Do stuff when things have been done
`

语意上是区块的完成,技术上来说,有一些方法在沟通时会需要特定权限、参数,使用handler可以知会该特定方法行为已经结束了。

public var completionHandler: (() -> Void)?

不过这边没有什麽参数要传,因此很简单这样写就可以了。
总之最後我们想要dismiss controller,回到最初的画面,因此呼叫popToRootViewController

ViewViewController

来到最後一个controller!
我们希望能看细节、删除功能。

首先宣告这个item、删除行为的handler、要放在画面上的两个元件,以及建立DB连线。

public var item: TodoListItem?
public var deletionHandler: (() -> Void)?

@IBOutlet var itemLabel: UILabel!
@IBOutlet var dateLabel: UILabel!

private var realm = try! Realm()

接着尝试做日期parsing,我们希望把日期换成字串,在这边使用static是由於date formatter预期会create a memory,那我们只会使用一次,不希望造成memory leak的现象。

static let dateFormatter: DateFormatter = {
    let dateFormatter = DateFormatter()
    dateFormatter.dateStyle = .medium
    return dateFormatter
}()

viewDidLoad

loading的时候,把元件内容都一并load进来,并且新增删除的按钮,按下时会触发didTapDelete方法。

override func viewDidLoad() {
    super.viewDidLoad()

    itemLabel.text = item?.item
    dateLabel.text = Self.dateFormatter.string(from: item!.date)

    navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .trash, target: self, action: #selector(didTapDelete))
}

didTapDelete

这个方法跟先前的didTapSaveButton类似,只是在资料库的行为改成删除。
然後也别忘记呼叫handler、回到主画面。

@objc func didTapDelete() {
    guard let item = self.item else {
        return
    }
    realm.beginWrite()
    realm.delete(item)
    try! realm.commitWrite()

    deletionHandler?()
    navigationController?.popToRootViewController(animated: true)
}

storyboard

一样的,我们得把程序逻辑跟相对应的画面bind起来。
首先加上class,指定为刚刚的viewViewControlller,并指定id。

接着加入两个label,拖拉至画面後分别加上constraints。
其中一个为上左右20、高70,另一个是上10、左右20、高70。

得到以下画面之後右键(or两指)点选,把程序中的IOutlet指定到相对应的UI元件。

ViewController

最後,终於到了最後,我们回到主画面程序ViewController。

didSelectRowAt

点下某一个row的时候,呼叫instantiateViewController使用指定好的id创造一个新的viewController,将一些变数放进去,再呼叫pushViewController将该viewController放到receiver端stack中。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    tableView.deselectRow(at: indexPath, animated: true)

    let item = data[indexPath.row]

    guard let vc = storyboard?.instantiateViewController(identifier: "view") as? ViewViewController else {
        return
    }

    vc.item = item
    vc.deletionHandler = {[weak self] in
        self?.refresh()
    }
    vc.navigationItem.largeTitleDisplayMode = .never
    vc.title = item.item
    navigationController?.pushViewController(vc, animated: true)
}

结语

基本且阳春的to-do list就这麽做完了。
我在想是否有些功能与显示能被优化,或是改变呈现方式。
或是我应该放下执念,前往别的专案了呢?

若有任何不足或有误,欢迎指教 (゜▽゜;)

参考资源

  1. Class Realm (property beginWrite)
  2. Completion Handlers in Swift with Bob
  3. How could I create a function with a completion handler in Swift?

<<:  OpenStack 部属工具 2

>>:  分散式链路追踪 - Jaeger

[火锅吃到饱-16] 斗牛士二锅 - 台中文心店

官网有分店资讯 之前在脸书社团就看过版友分享过桃园店的用餐体验,平日午餐328的价位,提供6种肉品吃...

自动化 End-End 测试 Nightwatch.js 之踩雷笔记:上传档案

上传本机端的档案其实很简单,只是单纯的 setValue() 就好了。 browser.setVal...

[Day 20] - 『转职工作的Lessons learned』 - GraphQL (Hasura) - 身份级别权限设定

先前的GraphQL(Hasura)-Webhook身份验证有介绍到可以使用Webhook做身份级别...

[ Day 17 ] - Event 物件中的资讯

使用 addEventListener 进行事件监听, 此时 EvetnListener 会建立事件...

Day10:选择排序(Selection Sort)

选择排序(Select Sort) 选择排序是重复进行「将数列中最小值,与左边的值对调」,一直保持由...