如何从 SwiftUI 中的 NSManagedObject 中删除重复日期(没有时间)
How to remove duplicate dates (without time) from NSManagedObject in SwiftUI
我有这个 class,它是从 Xcode/核心数据自动生成的,用于名为 Activity 的核心数据实体。
@objc(Activity)
public class Activity: NSManagedObject {
}
extension Activity {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Activity> {
return NSFetchRequest<Activity>(entityName: "Activity")
}
@NSManaged public var name: String
@NSManaged public var date: Date
}
我怎样才能得到具有不同日期(没有时间)的结果,只有一个视图没有重复日期,而另一个视图有所有日期(未过滤)?
我不确定,如果我需要修改我的 Activity Class 并使用自定义函数扩展它,或者我是否可以对 @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Activity.name, ascending: true)]) var activites: FetchedResults<Activity>
应用过滤器,或者如果我需要直接在 List(activities, id: \.self)
.
中处理请求的结果
我需要同时拥有所有日期和筛选日期的灵活性。过滤后的活动不需要名称,也不能是唯一的。我只想要一个包含日期(没有时间)字符串的列表。未过滤的列表需要名称和日期。
例如:
- 2020-06-22
- 2020-05-20
- 2020-05-20
- 2020-05-20
- 2020-03-02
应该过滤到
- 2020-06-22
- 2020-05-20
- 2020-03-02
你描述的问题并没有那么简单。
您使用的 Date
是从某个时间点以秒为单位定义的时间戳。它与任何日历无关。
但是,您显示的字符串是基于日历的,并且是对给定时间戳的解释。
因此,当使用日历(包括时区)时,两个不同的用户对单个日期的解释可能会有所不同,主要取决于时区。
我认为数据库将 Date
对象存储为 64 位浮点值。因此,要获得过滤日期,您基本上是在要求获得所有唯一值,其中这些值首先由一些荒谬的“日历”算法四舍五入。祝你好运。
最简单的方法是在内存中执行此操作。您可以获取所有条目,然后使用字典对您的条目进行分组:
func sortEntriesByDays(_ activities: [Activity]) -> [Date: [Activity]] {
let calendar = Calendar.autoupdatingCurrent
var sortedItems: [Date: [Activity]] = [Date: [Activity]]()
activities.forEach { activity in
let dayStartDate = calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
var activities: [Activity] = sortedItems[dayStartDate] ?? [Activity]()
activities.append(activity)
sortedItems[dayStartDate] = activities
}
return sortedItems
}
您只需调用 .keys
即可从此方法的结果中获取所有唯一日期。
这可能是最简单、最安全的解决方案。唯一的问题是当你的数据库中有很多条目时,你可能不想加载所有(或很多)条目而只是为了显示一些。在这些情况下,获取结果控制器非常有用,但要使用它,您可能需要更改数据库。
一种方法是在 Activity
中存储 2 个日期。一个是您已经存储的实际日期,另一个是它所属日期的开始。您可以简单地创建一个可以设置两个日期的 setDate
方法;第二个简单地使用代码:calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
.
一种非常相似的方法是只使用格式 yyyy-MM-dd
添加一个字符串,正如您所描述的那样。与之前的想法没有太大变化。
然后另一种方法是创建另一个实体 Day
,它与您的 activity 对象保持多对一关系。所以每个 activity 都应该准确地引用一天。因此,当一个 activity 应该被插入到数据库中时,它应该尝试找到一个对应的日期对象并与之连接。如果没有这样的 Day 对象,则需要创建一个。修改对象时,需要重新检查它是否属于同一天。当 activity 从 Day 对象中删除时,您还需要检查是否还有其他活动,并在没有活动时从数据库中删除 Day 对象。
但是,无论您使用这 3 个选项中的哪个选项,当用户更改时区(可能是由于旅行)时,您都可能会遇到问题。当发生这种情况时,代码 calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
将产生不同的结果,并且 activity 现在可能应该属于不同的 Day 对象。您可以检测到该更改并重组您的数据库...
我有这个 class,它是从 Xcode/核心数据自动生成的,用于名为 Activity 的核心数据实体。
@objc(Activity)
public class Activity: NSManagedObject {
}
extension Activity {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Activity> {
return NSFetchRequest<Activity>(entityName: "Activity")
}
@NSManaged public var name: String
@NSManaged public var date: Date
}
我怎样才能得到具有不同日期(没有时间)的结果,只有一个视图没有重复日期,而另一个视图有所有日期(未过滤)?
我不确定,如果我需要修改我的 Activity Class 并使用自定义函数扩展它,或者我是否可以对 @FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Activity.name, ascending: true)]) var activites: FetchedResults<Activity>
应用过滤器,或者如果我需要直接在 List(activities, id: \.self)
.
我需要同时拥有所有日期和筛选日期的灵活性。过滤后的活动不需要名称,也不能是唯一的。我只想要一个包含日期(没有时间)字符串的列表。未过滤的列表需要名称和日期。
例如:
- 2020-06-22
- 2020-05-20
- 2020-05-20
- 2020-05-20
- 2020-03-02
应该过滤到
- 2020-06-22
- 2020-05-20
- 2020-03-02
你描述的问题并没有那么简单。
您使用的 Date
是从某个时间点以秒为单位定义的时间戳。它与任何日历无关。
但是,您显示的字符串是基于日历的,并且是对给定时间戳的解释。
因此,当使用日历(包括时区)时,两个不同的用户对单个日期的解释可能会有所不同,主要取决于时区。
我认为数据库将 Date
对象存储为 64 位浮点值。因此,要获得过滤日期,您基本上是在要求获得所有唯一值,其中这些值首先由一些荒谬的“日历”算法四舍五入。祝你好运。
最简单的方法是在内存中执行此操作。您可以获取所有条目,然后使用字典对您的条目进行分组:
func sortEntriesByDays(_ activities: [Activity]) -> [Date: [Activity]] {
let calendar = Calendar.autoupdatingCurrent
var sortedItems: [Date: [Activity]] = [Date: [Activity]]()
activities.forEach { activity in
let dayStartDate = calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
var activities: [Activity] = sortedItems[dayStartDate] ?? [Activity]()
activities.append(activity)
sortedItems[dayStartDate] = activities
}
return sortedItems
}
您只需调用 .keys
即可从此方法的结果中获取所有唯一日期。
这可能是最简单、最安全的解决方案。唯一的问题是当你的数据库中有很多条目时,你可能不想加载所有(或很多)条目而只是为了显示一些。在这些情况下,获取结果控制器非常有用,但要使用它,您可能需要更改数据库。
一种方法是在 Activity
中存储 2 个日期。一个是您已经存储的实际日期,另一个是它所属日期的开始。您可以简单地创建一个可以设置两个日期的 setDate
方法;第二个简单地使用代码:calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
.
一种非常相似的方法是只使用格式 yyyy-MM-dd
添加一个字符串,正如您所描述的那样。与之前的想法没有太大变化。
然后另一种方法是创建另一个实体 Day
,它与您的 activity 对象保持多对一关系。所以每个 activity 都应该准确地引用一天。因此,当一个 activity 应该被插入到数据库中时,它应该尝试找到一个对应的日期对象并与之连接。如果没有这样的 Day 对象,则需要创建一个。修改对象时,需要重新检查它是否属于同一天。当 activity 从 Day 对象中删除时,您还需要检查是否还有其他活动,并在没有活动时从数据库中删除 Day 对象。
但是,无论您使用这 3 个选项中的哪个选项,当用户更改时区(可能是由于旅行)时,您都可能会遇到问题。当发生这种情况时,代码 calendar.date(from: calendar.dateComponents([.year, .month, .day], from: activity.date))!
将产生不同的结果,并且 activity 现在可能应该属于不同的 Day 对象。您可以检测到该更改并重组您的数据库...