【发布时间】:2021-03-29 21:56:36
【问题描述】:
我正在尝试在我的 NotesApp 中从领域中删除笔记并遇到此错误:“只能从它所属的领域中删除一个对象”。此笔记之前也保存在 Realm 和 可以通过点击我的 FSCalendar 中的日期在我的 TableView 中显示它。我试图用realm.create(item)替换realm.add(item),但也得到了错误:“无法将'T'类型的值转换为预期的参数类型'Object.Type'(又名'RealmSwiftObject.Type') ”。我是编程新手,所以任何帮助将不胜感激。以下是相关代码:
in my ToDoListItem.swift
class ToDoListItem: Object {
@objc dynamic var noteName: String = ""
@objc dynamic var date: Date = Date()
@objc dynamic var descriptionText: String = ""
@objc dynamic var noteImage = Data()
init(date: Date, noteName: String) {
self.date = date
self.noteName = noteName
}
override init() {
self.noteName = ""
self.date = Date()
self.descriptionText = ""
self.noteImage = Data()
}
}
in my RealmManager.swift
class RealmManager {
static let shared = RealmManager()
private let realm = try! Realm()
func write<T: Object>(item: T) {
realm.beginWrite()
realm.add(item)
try! realm.commitWrite()
}
func getObjects<T: Object>(type: T.Type) -> [T] {
return realm.objects(T.self).map({ $0 })
}
func delete<T: Object>(item: T) {
try! realm.write {
realm.delete(item)
}
}
}
in my ViewController where i can edit and delete the notes
@IBAction func didTapDelete() {
let note = ToDoListItem()
RealmManager.shared.delete(item: note)
self.deletionHandler?()
navigationController?.popToRootViewController(animated: true)
}
and finally in my TableViewController where the notes are displayed (honestly i think the problem is hidden here but cannot find it...
@IBOutlet var tableViewPlanner: UITableView!
@IBOutlet var calendarView: FSCalendar!
private var data = [ToDoListItem]()
var datesOfEvents: [String] {
return self.data.map { DateFormatters.stringFromDatestamp(datestamp: Int($0.date.timeIntervalSince1970)) }
}
var items: [ToDoListItem] = []
func getCount(for Date: String) -> Int {
var count: [String : Int] = [:]
for date in datesOfEvents {
count[date] = (count[date] ?? 0) + 1
}
return count[Date] ?? 0
}
func getEventsForDate(date: Date) -> [ToDoListItem] {
let string = DateFormatters.stringFromDatestamp(datestamp: Int(date.timeIntervalSince1970))
return self.data.filter {DateFormatters.stringFromDatestamp(datestamp: Int($0.date.timeIntervalSince1970)) == string }.sorted(by: {$0.date < $1.date})
}
override func viewDidLoad() {
super.viewDidLoad()
calendarView.rounding()
tableViewPlanner.rounding()
data = RealmManager.shared.getObjects(type: ToDoListItem.self)
self.items = self.getEventsForDate(date: Date())
calendarView.delegate = self
calendarView.dataSource = self
tableViewPlanner.delegate = self
tableViewPlanner.dataSource = self
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
self.calendarView.select(Date())
self.calendarView.reloadData()
refresh()
}
//MARK:- TableView Data Source
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.items.count //data.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: K.plannerCellIdentifier, for: indexPath) as! NoteTableViewCell
let note = self.items[indexPath.row]
cell.configureCell(note: note)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
let note = data[indexPath.row]
guard
let vc = storyboard?.instantiateViewController(identifier: K.infoVCIdentifier) as? InfoViewController else { return }
vc.note = note
vc.deletionHandler = { [weak self] in
self?.refresh()
}
vc.title = note.noteName
navigationController?.pushViewController(vc, animated: true)
}
//MARK:- User Interaction
@IBAction func didTapAddButton() {
guard
let vc = storyboard?.instantiateViewController(identifier: K.entryVCIdentifier) as? EntryViewController else { return }
vc.completionHandler = { [weak self] in
self?.refresh()
}
vc.title = K.entryVCTitle
navigationController?.pushViewController(vc, animated: true)
}
func refresh() {
DispatchQueue.main.async {
self.data = RealmManager.shared.getObjects(type: ToDoListItem.self)
self.tableViewPlanner.reloadData()
self.calendarView.reloadData()
}
}
}
扩展PlannerViewController:FSCalendarDelegateAppearance & FSCalendarDataSource {
func calendar(_ calendar: FSCalendar, appearance: FSCalendarAppearance, eventDefaultColorsFor date: Date) -> [UIColor]? {
let dateString = DateFormatters.yearAndMonthAndDateFormatter.string(from: date)
if self.datesOfEvents.contains(dateString) {
return [UIColor.blue]
}
return [UIColor.white]
}
func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) {
self.items = self.getEventsForDate(date: date)
self.tableViewPlanner.reloadData()
}
func calendar(_ calendar: FSCalendar, numberOfEventsFor date: Date) -> Int {
let dateString = DateFormatters.yearAndMonthAndDateFormatter.string(from: date)
let count = self.getCount(for: dateString)
self.tableViewPlanner.reloadData()
return count
}
}
【问题讨论】:
-
您正在尝试删除 Realm 中不存在的对象。查看您的
tapToDelete函数。您首先在内存中创建一个新项目let note = ToDoListItem(),然后尝试将其从领域RealmManager.shared.delete(item: note)中删除。您必须将其写入 Realm 才能将其从 Realm 中删除。 -
此外,此代码
realm.objects(T.self).map({ $0 })将成为问题,因为您将实时更新领域对象转换为数组,然后将它们与领域断开连接,因此它们不再实时更新。此外,Realm Results 会延迟加载到数千个对象,对内存的影响很小。当将其转换为数组时,所有项目都加载到内存中,这可能会使设备不堪重负并导致其崩溃。见this answer -
@Jay 非常感谢!那么,我究竟需要如何更改我的 tapToDelete() 方法?我的“let note”没用,我如何到达 Realm 中的真实对象?从我的 TableViewController 中,我将注释(通过单击它)发送到我的 InfoViewController,我可以在其中编辑或删除此注释(此处:github.com/NikolaiBorisov/DailyPlanner/blob/main/DailyPlanner/…)。以及如何更改此代码“realm.objects(T.self).map({ $0 })”以避免这些问题?抱歉这些问题,我只是想逐步了解我需要做什么。谢谢=)
-
在高层次上,您的 tableView 由数据源支持 - 通常是数组或领域集合(结果或列表)。在该数组或列表中,您将拥有包含 tableView 中显示的任何数据的对象。如果点击删除表中的第 1 行,则需要获取行索引,在本例中为 1,从 dataSource 中获取该对象,然后将其从 Realm 中删除,并将其从 dataSource 中删除。对此有一些警告;如果您的 dataSource 是 Results 对象,它将自动更新。如果您观察对象,则通过观察事件更新列表。
-
@Jay 非常感谢!