如何使用 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 数据?

如何在 Swift for Realm 模型中设置主键

如何在Swift中返回Realm列表?

在同一个项目中同时使用 Realm Swift 和 Realm Objective-C

在Realm swift中重命名类的最佳方法