当我使用realm.objects()检索父对象时,我试图检索按特定顺序排序的嵌套对象。同样重要的是,如果修改了任何嵌套对象,请保持排序顺序。
我搜索了相关问题,但它们要么过时,要么与我描述的问题不完全相同
这是一个例子:我在Realm中有一个“用户”,每个用户都有一个“任务”(为清楚起见,省略了多余的字段)
let arr2 = [[1, 2], [2, 3], [4, 5], [5, 6], [7, 8], [1, 8, 9], [10, 9], [9, 6]]
print(group(arr: arr2))
我创建了几个用户,然后为任何给定用户添加了任务(UI中的表格,其中包含每个用户的部分,该用户的任务作为该用户部分中的行,按优先级排序)。
默认优先级从10开始,可以随时在1-10的范围内更改。
当我检索用户时:
class task: Object {
@objc dynamic var priority = 10
}
class user: Object {
@objc dynamic var name = ""
let tasks = List<task>()
}
我想检索按优先级排序的任务。
请注意,优先级是在最初检索用户后修改的(意味着结果的任务对象的优先级在realm.write()下更改)。为了澄清代码中某位用户的任务,我执行以下操作:
// (1)
users = realm.objects(user.self).sorted(byKeyPath: "name")
这意味着应该始终按优先级对用户的任务列表进行排序,而不需要重复上面的(1)。我无法对user.tasks属性进行排序,因为它是一个“ let”变量。
请注意,用户和任务对象都具有排序顺序。
我在更新上面的“优先级”之后可以对任务做索引(删除/添加),但是还没有尝试过。但是,不是手动进行此操作(并假设它可以正常工作,并且假设在reshuflle旁边没有删除/添加“任务”,...),并不是说ORM背后的整个想法是事情简单吗?
是否要这样做?随着领域的扩展? ???公开有关替代方法与嵌套对象的建议。
答案 0 :(得分:1)
一个很好的问题和答案,真正展示了Realms的实时更新功能。
重新确定问题
用户有任务,我们希望按顺序处理这些任务 列表中,如果订单有变化,请按新订单保持订单顺序
使用问题中提供的两个类,我们有一个按钮,该按钮调用一个函数来查询用户的领域并将该用户存储在var类中
var myUser: UserClass!
func loadUser() {
if let realm = gGetRealm() { //my code to connect to Realm
let userResults = realm.objects(UserClass.self)
if userResults.count > 0 {
let user = userResults[0]
self.myUser = user
}
}
}
然后是一个按钮,该按钮调用一个函数以简单地打印出用户的任务,按优先级排序
func printOrderedTasks() {
let sortedTasks = self.myUser.tasks.sorted(byKeyPath: "priority")
for task in sortedTasks {
print(task)
}
}
因此,在此示例中,我创建了4个任务,并将它们添加到用户任务列表中,并将用户写入领域,优先级初始顺序为:10、0、1、4
然后loadUser加载并存储第一个可用的用户,并将其分配给var类。
printOrderedTasks以升序输出任务。因此,在加载用户后,单击printOrderedTasks,输出为
0
1
4
10
然后,使用Realm Studio将1更改为6,然后再次单击printOrderedTasks,输出为
0
4
6
10
无需重新加载任何内容。
领域对象是实时更新的,只要您在代码中对其进行引用,任何更改都会实时反映。
您可以通过在该对象上添加观察者来扩展此范围,Realm会将该事件通知应用程序,您可以在该事件中重新加载tableView或让用户知道更改。
编辑:
要更进一步,用户任务也是实时更新对象,如果您对它们进行排序,则这些结果将保持其排序。
例如,让我们重写上面的代码,以跟踪维护实时排序的用户任务。我重新编写了上面的代码,并删除了用户类var,并添加了一个任务类var。请注意,我们永远不需要重新排序任务,排序顺序是最初设置的,从那时起它们将保持排序状态。
var myUserTasks: Results<TaskClass>!
func loadUserAndGetTasks() {
if let realm = gGetRealm() {
let userResults = realm.objects(UserClass.self)
if userResults.count > 0 {
let user = userResults[0]
self.myUserTasks = user.tasks.sorted(byKeyPath: "priority")
}
}
}
func printTasks() {
for t in self.myUserTasks {
print(t)
}
}
如上所述,初始顺序为10、0、1、4。然后,如果我们使用Realm Studio将1更改为6,然后运行printTasks函数,您将看到排序自动完成,因为结果是实时更新的。
0
4
6
10
这里很酷的事情是,您不需要继续使用任务-它们会保持排序顺序。
答案 1 :(得分:1)
@Jay的答案一如既往地很棒,但我会采纳他的建议,并将其作为用户对象的固有内容。这是我处理此类需求的“常规”方式。
正如您所说,user
对象tasks
属性是let
,但这就是定义Realm对象的方式。这并不是说您无法添加自己的计算属性来控制对对象的访问。
如果您只想将任务显示为有序列表,请添加一个属性,例如
extension user
{
var orderedTasks: Results<task>
{
return tasks.sorted(byKeyPath: "priority")
}
}
然后始终使用该属性来访问任务。使用扩展名是我自己的风格-我只将数据声明保留在类声明中,然后添加具有任何计算出的属性或函数的扩展名-但您可以直接将声明添加到类定义中。