【问题标题】:MacOs table with SwiftUI: NSTableView, NSViewControllerRepresentable and Core data update使用 SwiftUI 的 MacOs 表:NSTableView、NSViewControllerRepresentable 和 Core 数据更新
【发布时间】:2022-07-14 05:58:14
【问题描述】:

我正在为 MacOS 创建个人银行账户应用。 我想显示一个包含交易的表格。我开始使用List,但列并没有很好地对齐。 我更改为 NSTableView 包裹在 NSViewControllerRepresentable 中。它工作正常。但是当我保存核心数据时,表格没有更新。 现在我想将核心数据更新连接到NSTableView更新以查看表中的变化。

如何做到这一点?

AccountTransactionTableView:

import Foundation
import SwiftUI
import CoreData
import Cocoa

struct AccountTransactionTableView: NSViewControllerRepresentable {
    typealias NSViewControllerType = AccountTransactionTableViewController

    @State var showSettingsModalView: Bool = false

    let account: BankAccount
    let month: Int
    let year: Int

    init(account: BankAccount, month: Int, year: Int) {
        self.account = account
        self.month = month
        self.year = year
    }

    func makeNSViewController(context: Context) -> AccountTransactionTableViewController {
        return AccountTransactionTableViewController(account: account, month: month, year: year)
    }

    func updateNSViewController(_ nsViewController: AccountTransactionTableViewController, context: Context) {

    }
}

AccountTransactionTableViewController:

class AccountTransactionTableViewController: NSViewController, NSTableViewDelegate, NSTableViewDataSource {
    let account: AbstractAccount
    @FetchRequest<TransactionEntry> private var entries: FetchedResults<TransactionEntry>

    var initialized = false
    let scrollView = NSScrollView()
    let tableView = NSTableView()
    let startDate: Date
    let endDate: Date

    init(account: AbstractAccount, month: Int, year: Int) {
        self.account = account

        self.startDate = DateTool.firstDayOfMonth(year: year, month: month)
        self.endDate = DateTool.endOfMonth(year: year, month: month)

        self._entries = FetchRequest<TransactionEntry>(
            entity: TransactionEntry.entity(),
            sortDescriptors: [NSSortDescriptor(keyPath: \TransactionEntry.transaction!.date, ascending: true)],
            predicate: NSPredicate(format: "account.name == %@ and transaction.date >= %@ and transaction.date <= %@", account.name!, startDate as CVarArg, endDate as CVarArg)
        )

        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func loadView() {
        self.view = NSView()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func viewDidLayout() {
        if !initialized {
            initialized = true
            setupView()
            setupTableView()
        }
    }

    func setupView() {
        self.view.translatesAutoresizingMaskIntoConstraints = true
    }

    func setupTableView() {
(...)
    }

    func numberOfRows(in tableView: NSTableView) -> Int {
        return entries.count
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let entry = entries.map { $0 }[row]
        let transactionCell = AccountTransactionCell(entry: entry, account: account, collapsed: false)
        let cell = NSTableCellView()
    
        let text = NSTextField()
        switch tableColumn!.identifier.rawValue {
        case "date":
            text.stringValue = "\(transactionCell.date)"
        case "category":
            text.stringValue = "\(transactionCell.category)"
        case "details":
            text.stringValue = "\(transactionCell.details)"
        case "debits":
            text.stringValue = "\(transactionCell.debit)"
            text.alignment = .right
        case "credits":
            text.stringValue = "\(transactionCell.credit)"
            text.alignment = .right
        default:
            text.stringValue = "-"
        }

        cell.addSubview(text)
        text.drawsBackground = false
        text.isBordered = false
        text.translatesAutoresizingMaskIntoConstraints = false
        cell.addConstraint(NSLayoutConstraint(item: text, attribute: .left, relatedBy: .equal, toItem: cell, attribute: .left, multiplier: 1, constant: 0))
        cell.addConstraint(NSLayoutConstraint(item: text, attribute: .right, relatedBy: .equal, toItem: cell, attribute: .right, multiplier: 1, constant: 0))
        return cell
    }

    func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
        let rowView = NSTableRowView()
        rowView.isEmphasized = false
        return rowView
    }
}    

AccountTransactionCell 是一个格式化结构体。

感谢您的帮助:-)

【问题讨论】:

    标签: swift xcode swiftui nstableview


    【解决方案1】:

    一旦保存在 Core Data 中,您必须调用 tableView.reloadData()

    这里有很好的解释:
    https://developer.apple.com/documentation/appkit/nstableview/1528382-reloaddata

    NSViewControllerRepresentable 为您提供的函数中可能需要调用它:

    func updateNSViewController(_ nsViewController: AccountTransactionTableViewController, context: Context) {
        nsViewController.tableView.reloadData()
    }
    

    重要提示: 仅当 Representable 包含对支持表的数据的引用时才会调用上述内容(也就是 @FetchRequest private var entries 存在于您的 Representable 类中,而不是AppKit 类。)

    如果您想将 @FetchRequest 属性包装器保留在 AppKit ViewController 中,那么您必须以另一种方式观察对 entries var 的更改,以使对象能够被感知,或者挂钩到不同的事件并以另一种方式致电reloadData()

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-20
      相关资源
      最近更新 更多