如何使用 Realm 选择当前项目以从 Swift 中的数组中删除它
Posted
技术标签:
【中文标题】如何使用 Realm 选择当前项目以从 Swift 中的数组中删除它【英文标题】:How to select the current item to delete it from an array in Swift using Realm 【发布时间】:2022-01-16 14:18:05 【问题描述】:所以,我尝试通过互联网和 *** 寻找答案,但我不确定要寻找什么,所以答案可能已经共享。所以我很抱歉,因为我是菜鸟。但是,我仍然需要帮助。 (拜托!)我正在开发一个应用程序,其中包含一个充满零件的表格视图,以及一个详细的零件页面,其中提供了零件的详细信息(零件名称、零件编号、描述等)
我在页面末尾有一个删除按钮,当您单击它时,它会询问您是否要删除,您确定吗?如果用户说是,则部分删除,但删除 仅从 tableview 中删除了最后一个项目,即最近添加的项目。我知道,是因为我调用了以下函数:
func deletePart()
if let partToDelete = getPartsArray().last
try! realm.write
realm.delete(partToDelete)
with 'getPartsArray().last'
我正在尝试查看如何删除 tableview 中当前选定的部分。现在,我可以选择顶部的第二部分,如果我单击该部分的删除按钮,它将始终从 tableview 中删除最后一部分。
这里是 getPartsArray 函数的代码:
func getPartsArray() -> [PartInfo]
return getAllParts().map $0
我(笨拙地)已经尝试过:使用 'getPartsArray().current' 显然这不是一回事,哈哈。
我也在想,既然我使用的是 REALM / Mongo DB,我可以通过它的 ID 找到零件吗?然后删除它?但我也不确定如何找到当前选择部分的 id。
任何帮助将不胜感激。谢谢!
编辑:这是我的 TableView 代码:
//
// ViewAllPartsViewController.swift
// PartKart
//
// Created by Kiarra Julien on 10/20/21.
//
import Foundation
import UIKit
class ViewAllPartsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CurrencyFormatter
private var brain = PartKartBrain()
private var parts = [PartInfo]()
@IBOutlet var tableView: UITableView!
@IBAction func returnHome()
dismiss(animated: true, completion: nil)
override func viewDidLoad()
super.viewDidLoad()
let nib = UINib(nibName: "DemoTableViewCell", bundle: nil)
tableView.register(nib, forCellReuseIdentifier: "DemoTableViewCell")
tableView.delegate = self
tableView.dataSource = self
parts = brain.getPartsArray()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
parts.count
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
let cell = tableView.dequeueReusableCell(withIdentifier: "DemoTableViewCell", for: indexPath) as! DemoTableViewCell
cell.partNameLabel.text = parts[indexPath.row].partName
// Convert string value to double
cell.partCostLabel.text = formatCurrency(value: parts[indexPath.row].partCost)
// String(format: "$%.2f", parts[indexPath.row].partCost)
cell.purchaseDateLabel.text = parts[indexPath.row].purchaseDate
// cell.textLabel?.text = parts[indexPath.row].partName
// cell.textLabel?.numberOfLines = 0countTotalParts()
// cell.textLabel?.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.headline)
return cell
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
tableView.deselectRow(at: indexPath, animated: true)
performSegue(withIdentifier: "showPartDetails", sender: parts[indexPath.row])
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
if let viewcontroller = segue.destination as? PartDetailsViewController
viewcontroller.part = sender as? PartInfo
这就是我所说的删除部分:
class PartDetailsViewController: UIViewController, CurrencyFormatter
//Store Information Labels
@IBOutlet weak var storeNameLabel: UILabel!
@IBOutlet weak var storeNumLabel: UILabel!
@IBOutlet weak var storeAddrLabel: UILabel!
//Part Information Labels
@IBOutlet weak var partNameLabel: UILabel!
@IBOutlet weak var partNumLabel: UILabel!
@IBOutlet weak var partDescLabel: UILabel!
@IBOutlet weak var partCostLabel: UILabel!
@IBOutlet weak var partQtyLabel: UILabel!
@IBOutlet weak var purchaseDateLabel: UILabel!
@IBOutlet weak var hasWarrantySwitch: UISwitch!
@IBOutlet weak var warrantyLengthLabel: UILabel!
//Mechanic Information Labels
@IBOutlet weak var mechanicNameLabel: UILabel!
@IBOutlet weak var mechanicNumLabel: UILabel!
@IBOutlet weak var mechanicAddrLabel: UILabel!
@IBOutlet weak var laborCostLabel: UILabel!
@IBOutlet weak var serviceDateLabel: UILabel!
var part: PartInfo?
let brain = PartKartBrain()
@IBAction func deletePartBtn(_ sender: UIButton)
// Declare Alert message
let dialogMessage = UIAlertController(title: "Confirm", message: "Are you sure you want to delete this part?", preferredStyle: .alert)
// Create OK button with action handler
let ok = UIAlertAction(title: "OK", style: .default, handler: (action) -> Void in
print("Ok button tapped")
// I CALL DELETE PART RIGHT HEREEE!
self.brain.deletePart()
// delay and then dismiss the page
let delayInSeconds = 0.5
DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds) [unowned self] in
dismiss(animated: true, completion: nil)
)
// Create Cancel button with action handlder
let cancel = UIAlertAction(title: "Cancel", style: .cancel) (action) -> Void in
print("Cancel button tapped")
//Add OK and Cancel button to dialog message
dialogMessage.addAction(ok)
dialogMessage.addAction(cancel)
// Present dialog message to user
self.present(dialogMessage, animated: true, completion: nil)
override func viewDidLoad()
super.viewDidLoad()
title = part?.partName
//Set the Store Info Labels Equal to actual data
storeNameLabel.text = part?.partName
storeNumLabel.text = part?.storeNumber
storeAddrLabel.text = part?.storeAddress // < ---- The address is cut off the screen!
//Set the Part Info Labels Equal to actual data
partNameLabel.text = part?.partName
partNumLabel.text = part?.partNumber
partDescLabel.text = part?.partDescription
if let partCost = part?.partCost
partCostLabel.text = formatCurrency(value: partCost)
if let partQty = part?.partQuantity
partQtyLabel.text = String(partQty)
purchaseDateLabel.text = part?.purchaseDate
//If there's no warranty, display 'N/A' instead
if part?.hasWarranty == true
hasWarrantySwitch.isOn = true
warrantyLengthLabel.text = part?.warrantyLength
else
hasWarrantySwitch.isOn = false
warrantyLengthLabel.text = "N/A"
//Set the Mechanic Info Labels Equal to actual data
mechanicNameLabel.text = part?.mechanicName
mechanicNumLabel.text = part?.mechanicNumber
mechanicAddrLabel.text = part?.mechanicAddress
//laborCostLabel.text = part?.laborCost
if let laborCost = part?.laborCost
laborCostLabel.text = formatCurrency(value: laborCost)
serviceDateLabel.text = part?.serviceDate
【问题讨论】:
您需要向我们展示您的更多代码,特别是您在 tableview 中的视图以及您调用 deletePart() 的位置。 @workingdog 好的,我已经更新了我的代码。 【参考方案1】:让我把问题告诉你
“如何从我的表格视图中删除选定的行”?
如果是这个问题,请提供一个简单的答案
首先,在使用 Realm 时不要这样做
return getAllParts().map $0
Realm 对象被延迟加载到 Results 对象中。一旦您针对 map、reduce 等高级函数(将它们存储在数组中)运行它们,它们就会全部加载到内存中,如果您有一个大数据集,这将使设备不堪重负。此外,如果您有排序等,您的对象将与底层 Realm 数据不同步。
最好的办法是利用 Realm Results 作为 tableView 数据源 - 它的行为很像数组。
所以这里有一个 viewController 类,它有一个部分 Results 对象作为 tableView 数据源
class InStockVC: NSViewController, NSTableViewDelegate, NSTableViewDataSource
var partsNotificationToken: NotificationToken!
var partsResults: Results<PartsClass>! //the tableView dataSource
假设用户点击或选择第 2 行,然后点击或单击“删除”
//pseudocode
let selectedRow = tableView.selectedRow
let part = partResults[selectedRow]
try! realm.write
realm.delete(part)
上面的代码判断表格中的哪一行被选中,从Results中获取part对象,然后告诉Realm删除它。
一旦从 Realm 中删除该对象,partsResults 对象会反映该更改,并且该对象会自动删除!您唯一需要做的就是在 UI 中反映这种变化。
有很多方法可以处理动画等,但为了简单起见,我们只需重新加载 tableView 以便不再显示已删除的行。
注意,在上面的代码中,还有一个var partsNotificationToken: NotificationToken!
,该令牌是结果对象的观察者——当底层数据中的某些内容发生变化时,结果对象也会发生变化,并且通知令牌会触发一个观察者动作来处理那个改变。这是一个示例观察者
self.partsNotificationToken = self.partsResults.observe changes in
switch changes
case .initial:
self.tableView.reloadData() //update the tableview after data is initially loaded
case .update(_, _, _, _):
self.tableView.reloadData() //update the tableView after changes
【讨论】:
以上是关于如何使用 Realm 选择当前项目以从 Swift 中的数组中删除它的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Realm swift 中过滤为当前日期创建的事件?
Realm (Swift):如何在迁移期间获取 MutableSet 数据?