我正在使用Realm快速创建要保存在用户设备上的收藏产品列表。
简而言之,两个视图控制器(A和B)嵌入在标签栏控制器中。
视图控制器A还具有一个“添加到收藏夹”按钮,用于将产品添加到Realm实例。
视图控制器B嵌入表视图以显示该Realm实例的结果。
问题是,当我从表格视图中删除某些产品时, 我回到查看控制器A时会遇到以下错误。
Terminating app due to uncaught exception 'RLMException', reason: 'Object has been deleted or invalidated
我已经阅读到,当尝试从Realm访问已删除的对象时,或者尝试重新添加以前删除的对象时,会发生此错误。这里似乎并非如此。
谢谢您的建议。
这是我的View Controller A中的“添加到收藏夹”按钮:
@IBAction func addToFavorites(_ sender: Any) {
let realm = try! Realm()
try! realm.write {
realm.add(currentProduct)
}
}
这是我的视图控制器B中的表视图代码:
class ViewControllerB: UIViewController, UITableViewDataSource, UITableViewDelegate {
let realm = try! Realm()
var favorites: Results<Product>!
@IBOutlet weak var favoritesTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
favoritesTableView.delegate = self
favoritesTableView.dataSource = self
favoritesTableView.rowHeight = 70
}
override func viewWillAppear(_ animated: Bool) {
favorites = realm.objects(Product.self)
favoritesTableView.reloadData()
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return favorites.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! favoriteTableViewCell
let product = favorites[indexPath.row]
cell.productName.text = product.name
cell.productCategory.text = product.category
return cell
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let product = favorites[indexPath.row]
try! realm.write {
realm.delete(product)
}
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.bottom)
}
}
编辑: 这是全视图控制器A
import UIKit
import RealmSwift
class ViewControllerA: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
var products = [Product]()
var scannedProduct = Product()
var currentProduct = Product()
let realm = try! Realm()
@IBOutlet weak var myCollectionView: UICollectionView!
@IBAction func addToFavorites(_ sender: Any) {
try! realm.write {
realm.add(currentProduct)
}
}
override func viewDidLoad() {
super.viewDidLoad()
myCollectionView.delegate = self
myCollectionView.dataSource = self
myCollectionView.isPagingEnabled = true
myCollectionView.backgroundColor = UIColor.blue
layout()
}
override func viewDidAppear(_ animated: Bool) {
currentProduct = scannedProduct
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return products.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! collectionCell
cell.productName.text = products[indexPath.item].name
cell.codeLabel.text = products[indexPath.item].code
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: myCollectionView.bounds.width, height: myCollectionView.bounds.height)
}
func layout() {
if let flowLayout = myCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.scrollDirection = .horizontal
flowLayout.minimumLineSpacing = 0
}
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let currentVisibleCell = myCollectionView.visibleCells.first
let currentIndex = myCollectionView.indexPath(for: currentVisibleCell!)?.item
currentProduct = products[currentIndex!]
}
}
答案 0 :(得分:0)
当尝试从Realm中访问已删除的对象时,情况似乎并非如此。
实际上...
try! realm.write { realm.delete(product) } tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.bottom)
这两行看起来不应该是这样。您会看到,Realm拥有NotificationToken
这个东西,并且有observe
个结果的能力。根据示例,它应如下所示:
var notificationToken: NotificationToken?
override func viewDidLoad() {
...
// Set results notification block
self.notificationToken = results.observe { (changes: RealmCollectionChange) in
switch changes {
case .initial:
// Results are now populated and can be accessed without blocking the UI
self.tableView.reloadData()
break
case .update(_, let deletions, let insertions, let modifications):
// Query results have changed, so apply them to the TableView
self.tableView.beginUpdates()
self.tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
self.tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
self.tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)
self.tableView.endUpdates()
break
case .error(let err): // this is probably not relevant in a non-sync scenario
break
}
}
如果有这个选项,从理论上讲,您可以删除自己的tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.bottom)
调用。每当发生更改(对Realm进行写操作)时,该观察者将使TableView保持最新状态。