我正在重建我的应用程序的CoreData堆栈,并将使用带有泛型的工作单元/存储库模式。
我的设置是BaseRepository<T:NSObject>
泛型类以及从基础存储库继承的CoreDataRepository<T:NSManagedObject>
类。
我有四种检索方法:getAll
,getAllSorted
,getAllFiltered
,最后是getAllFilteredSorted
。
CoreDataRepository
会将前三个get
方法链接到最后一个方法,并传入默认值。
以下是指定方法的定义:
func getAllFilteredSorted(predicate:(T) -> Bool, comparer:(T, T) -> Bool) -> T[]
{
let request = NSFetchRequest(entityName: entityName)
let results = context.executeFetchRequest(request, error: nil)
// TODO: Set predicate in Swift
// TODO: Set sort descriptors in Swift
return results as T[]
}
但是,我找不到使用这些函数闭包创建NSPredicate
或NSSortDescriptors
的方法。 NSManagedObjectContext.executeFetchRequest(...)
也没有超载来接受它们。
我知道可以在事实之后对进行排序/过滤,但这会减少我的CoreData请求的优化。我之前更愿意这样做。
关于如何实现这一目标的任何想法?如果我可以将闭包转换为适当的对象,我不介意,我只是不想改变我的函数的参数定义。
答案 0 :(得分:2)
归功于@David,但这属于答案,而不仅仅是评论。
不要做Swifty事情,因为他们是Swifty。为工作带来正确的工具。
您确实可以使用Swift闭包进行排序和过滤:
// NSPredicate:
init(block block: (AnyObject!, [NSObject : AnyObject]!) -> Bool) -> NSPredicate
// NSSortDescriptor:
init(key key: String, ascending ascending: Bool, comparator cmptr: NSComparator)
// where...
typealias NSComparator = (AnyObject!, AnyObject!) -> NSComparisonResult
但不要。
如果您的数据已经是内存中对象图的一部分,那么使用Swift中的闭包进行排序和过滤非常有用 - 您可以与这些对象交谈,询问他们的属性,并根据您获得的回复做出决策。您可以将此形式称为命令式编程 - 您正在告诉机器确切地要做什么(&#34;给我这些数据。获取此属性。与此相比属性。返回NSOrderedAscending
。&#34; ),它完全符合您的要求。
但是当您使用Core Data时,您正在使用的数据不一定是对象 - 它们可能是SQLite数据库中的行,或者归功于{{{ 1}}子类,实际上几乎任何东西,本地或远程。在这种情况下,命令式编程会中断...您不想从数据库中获取所有内容(或从任何地方获取),将每行转换为NSIncrementalStore
,从每个行读取属性等。 (想象一下,如果您的数据库特别大,或者您的Core Data存储由远程服务支持,会发生什么。)
相反,你想要的是描述性编程:告诉机器你通常想做什么,并让它弄清楚如何最好地完成结果。 (&#34;为我提供名称中包含&#39; foo&#39;或&#39;フー&#39;的项目,按创建日期按升序排序。&#34; )是NSManagedObject
和NSSortDescriptor
之类的类 - 它们是通用的(在Swift语言意义上不是通用的)方式来描述如何对数据进行排序和过滤。程序(或像Core Data这样的库)可以自由阅读这些描述并实现它们,但最适合于手头的任务。
在使用本地SQLite存储运行Core Data的情况下,您的谓词和排序描述符将变为SQL查询,因此无需实例化和处理对象 - 排序和过滤发生得更多有效地在后端,只有结果才需要构建对象。实际上,我相信如果您尝试使用SQL后端执行基于块/闭包的谓词或比较器,至少有一些Core Data API会给您一个错误。