一个受 SnapKit 启发的用于 iOS 和 OS X 的 Swift NSPredicate
DSL,由 KrakenDev 的人精心编写并创建。
如果您熟悉 SnapKit API 的直观性,那么您会喜欢 PrediKit 的感觉!
文档由 Jazzy 生成,您可以通过此链接方便地找到它:这里!
因为我想要这样!另外,因为创建 NSPredicate
很困难。当与 CoreData
一起工作时,您使用 NSPredicates
来获取持久化的对象。虽然 CoreData
已经很复杂了,但为什么要再使用一个复杂的字符串基础预设系统呢?
用于创建预设格式的语言完全是基于字符串的,这可能导致一系列问题。
NSPredicate
系统解析,那么什么都不会发生。它只是默默失败。至少我认为是这样。我目前在睡两个小时后撰写这篇文章。请别引用我。希望它解决了上述所有问题以及更多。目前,它
匹配
或不匹配
另一个值时语法正确,也都有一个冗余的API。builder
闭包都不需要捕获语义,因为每个闭包都是一个@noescape
闭包。如果你不知道这意味着什么,请到这里阅读 🤓。PrediKit可以通过以下任何一种方法集成到你的项目中:
如果你不愿使用上述依赖管理器,你可以手动将PrediKit集成到你的项目中。
首先,将这些命令复制并粘贴到终端
git clone https://github.com/KrakenDev/PrediKit.git
open PrediKit/Sources/
这将在Finder窗口中打开一个包含PrediKit所需重要文件的源文件夹。将这些文件夹拖放到你的项目中(最好放在名为“PrediKit”的文件夹中)并开始编写代码!由于你会直接将文件复制到项目中,因此在需要PrediKit的任何文件中都不需要import PrediKit
行。
这种方式的不便之处在于,你不能轻松地更新PrediKit。每次你想要获取最新和最好的版本时,都需要重复这些步骤!
PrediKit力求使创建NSPredicate
变得简单。深受来自SnapKit的API的启发,PrediKit的API对我的爱者来说极为相似。看看这个。以下示例创建了一个用于从CoreData
获取ManagedObject
的谓词。
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string("title").equals("The Almighty Kraken")
}
检查属性是否为nil
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string("title").equalsNil()
}
PrediKit还可以查询成员属性。比如说,你有一个类似于这样的类结构
class Captain: NSObject {
var name: String
}
class Ship: NSObject {
var captain: Captain
}
并且你想创建这些谓词
let someCaptain = Captain()
NSPredicate(format: "captain == %@ && captain.name == 'Chief Supreme'", someCaptain)
使用PrediKit创建上述内容既简单又易于表达
let someCaptain = Captain()
let predicate = NSPredicate(Ship.self) { includeIf
let includeIfShipCaptain = includeIf.member("captain", ofType: Captain.self)
includeIfShipCaptain.equals(someCaptain) &&
includeIfShipCaptain.string("name").equals("Chief Supreme")
}
PrediKit还重载了&&
、||
和!
运算符。这允许你组合并指定是否包括你的includers
(我知道这个名字很糟糕。欢迎提出建议)。
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
//Include any ManagedLegend instance if the property named "string" is NOT nil and does NOT equal "The Almighty Kraken"
!includeIf.string("title").equalsNil() &&
!includeIf.string("title").equals("The Almighty Kraken") &&
//Also include any ManagedLegend instance if the date property named "birthdate" is in the past or if the bool property "isAwesome" is true.
includeIf.date("birthdate").isEarlierThan(NSDate()) ||
includeIf.bool("isAwesome").isTrue()
}
甚至可以条件性地创建includers
!
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
let isKrakenQuery = includeIf.string("title").equals("The Almighty Kraken")
let birthdateQuery = includeIf.date("birthdate").isEarlierThan(NSDate())
let isAwesomeQuery = includeIf.bool("isAwesome").isTrue
if shouldCheckBirthdate {
(isKrakenQuery && birthdateQuery) || isAwesomeQuery
} else {
isKrakenQuery || isAwesomeQuery
}
}
我不知道你们,但SQL-style的IN
运算符很难理解。PrediKit使这一部分更易于阅读人类代码
let awesomePeeps = ["Kraken", "Cthulhu", "Voldemort", "Ember", "Umber", "Voldemort"]
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string("title").matchesAnyValueIn(awesomePeeps)
}
PrediKit还支持子查询谓词
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string("title").equals("The Almighty Kraken") &&
//Only include Krakens that have more than three hungry cerberus friends
includeIf.collection("cerberusFriends").subquery(ManagedCerberus.self) {
$0.bool("isHungry").isTrue()
return .IncludeIfMatched(.Amount(.IsGreaterThan(3)))
}
}
我个人非常喜欢在PrediKit中使用选择器扩展模式的变种。这允许你在使用API时避免拼写错误的属性名。它还允许你随意重命名选择器属性。通过重命名,PrediKit使用的每个选择器实例都应给出编译器错误,这样你就可以一口气完成工作,并且可以放心地知道你没有遗漏任何属性名,而且在重构时没有遗漏任何属性名。
import Foundation
extension Selector {
private enum Names: String {
case title
case birthdate
case age
case friends
case isAwesome
case isHungry
}
private init(_ name: Names) {
self.init(name.rawValue)
}
static let title = Selector(.title)
static let birthdate = Selector(.birthdate)
static let age = Selector(.age)
static let friends = Selector(.friends)
static let isAwesome = Selector(.isAwesome)
static let isHungry = Selector(.isHungry)
}
创建类似这样的选择器扩展后,PrediKit变得更加易于表达
//BEFORE
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string("title").equals("The Almighty Kraken")
}
//AFTER
let predicate = NSPredicate(ManagedLegend.self) { includeIf in
includeIf.string(.title).equals("The Almighty Kraken")
}
PrediKit采用MIT
许可证。查看LICENSE
文件了解更多信息。