当您的数据源是 Results 对象时,如何在表格视图中移动行?
Posted
技术标签:
【中文标题】当您的数据源是 Results 对象时,如何在表格视图中移动行?【英文标题】:How to move rows in a table view when your data source is a Results object? 【发布时间】:2021-10-29 18:47:32 【问题描述】:我有一个从结果对象中提取数据的表格视图。但是,因为您不能在 Results 对象中移动项目,所以我必须使用 List 对象在表格视图中移动行。
但是,如果您将数据从结果转换为列表对象(将列表对象用于表格视图),列表对象不再是反应式的。这意味着它只包含 Results 对象中的数据副本。
所以我的问题是: 当您的表格视图从结果对象中提取数据时,您如何在表格视图中移动行?
【问题讨论】:
如果您移动行,结果将自动更新。因此,只需在结果中添加一个观察者来刷新 tableView,当 Realm 更新时,这一切都会自动发生。您还可以在观察闭包中执行手动删除、插入和修改。见React To Changes 【参考方案1】:您需要为模型添加索引属性。要么,要么您需要定义一个新的 Realm 类,该类具有索引属性和对您要定义的对象的引用。我会推荐第一个,因为它更简单。这是执行此操作的一种方法。
我会实现一个协议,以便您可以将相同的逻辑应用于其他模型。
protocol IndexableObject: AnyObject
var index: Int get set
现在符合协议。
class MovingObject: Object, IndexableObject
@objc dynamic var name: String = ""
@objc dynamic var index: Int = 0
如果您向结果添加扩展名,那将会很有帮助。基本上你想要做的是提取索引在 [fromIndex, toIndex] 范围内的元素并将它们存储在一个数组中,这样你就可以在执行“移动”后更新索引。过滤器确保您只更新必要的索引,而不是结果集中的所有元素。
extension Results where Element: IndexableObject
func moveObject(from fromIndex: Int, to toIndex: Int)
let min = Swift.min(fromIndex, toIndex)
let max = Swift.max(fromIndex, toIndex)
let baseIndex = min
var elementsInRange: [Element] = filter("index >= %@ AND index <= %@", min, max)
.map $0
let source = elementsInRange.remove(at: fromIndex - baseIndex)
elementsInRange.insert(source, at: toIndex - baseIndex)
elementsInRange
.enumerated()
.forEach (index, element) in
element.index = index + baseIndex
在你的 UIableViewController 中使用会这样。
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
let realm = try! Realm()
try! realm.write
objects.moveObject(from: sourceIndexPath.row, to: destinationIndexPath.row)
只需确保按索引排序并将对象链接到通知块中的 UITableView。您应该在 Realm 的在线文档中找到有关如何完成此操作的大量信息。
lazy var objects: Results<MovingObject> =
let realm = try! Realm()
return realm.objects(MovingObject.self)
.sorted(by: \.index, ascending: true)
()
func observeObjects()
notificationToken = objects.observe [weak self] change in
self?.processChange(change)
【讨论】:
【参考方案2】:首先,你必须像这样定义Results
结构体。
struct Results
var items: [Int]
mutating func move(from: Int, to: Int)
let temp = items[from]
items[from] = items[to]
items[to] = temp
在 UITableViewDelegate 中,每次移动项目时,都会调用此方法并处理其中的数据更改
func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath
results.move(from: sourceIndexPath.item, to: proposedDestinationIndexPath.item)
return proposedDestinationIndexPath
【讨论】:
这不正确......好吧,它是正确的,但不适用于所提出的问题。 OP 正在使用 Realm Results 对象,该对象不可直接修改,而不是结构。【参考方案3】:您可以尝试对数组进行排序。
var results = [Results]()
所以在插入results
之后。尝试像这样对它们进行排序。
var filteredResults: [Result]
results.sorted(by: $0.id < $1.id )
这会将它们从最小 ID 到最大 ID 排序。
我的示例结果结构
struct Result
let id: Int
然后在你的DataSource 中使用这个数组而不是第一个数组。它将以相同的顺序显示在表格视图中。
【讨论】:
小心这个。在 Objc Realm 对象上运行 Swift 函数可以将结果与 Realm 分离,因此它们不会自动更新。更好的选择是使用 Realm.sorted(byKeyPath: "name"
函数进行排序。以上是关于当您的数据源是 Results 对象时,如何在表格视图中移动行?的主要内容,如果未能解决你的问题,请参考以下文章