Skip to content

Commit df27829

Browse files
authored
Merge pull request #716 from naithar/NSPredicate
2 parents 93d0018 + a576188 commit df27829

File tree

2 files changed

+90
-6
lines changed

2 files changed

+90
-6
lines changed

Foundation/NSPredicate.swift

Lines changed: 77 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ open class NSPredicate : NSObject, NSSecureCoding, NSCopying {
1515
private enum PredicateKind {
1616
case boolean(Bool)
1717
case block((Any?, [String : Any]?) -> Bool)
18-
// TODO: case for init(format:argumentArray:)
19-
// TODO: case for init(fromMetadataQueryString:)
18+
case format(String)
19+
case metadataQuery(String)
2020
}
2121

2222
private let kind: PredicateKind
@@ -26,19 +26,72 @@ open class NSPredicate : NSObject, NSSecureCoding, NSCopying {
2626
}
2727

2828
public required init?(coder aDecoder: NSCoder) {
29-
NSUnimplemented()
29+
guard aDecoder.allowsKeyedCoding else {
30+
preconditionFailure("Unkeyed coding is unsupported.")
31+
}
32+
33+
let encodedBool = aDecoder.decodeBool(forKey: "NS.boolean.value")
34+
self.kind = .boolean(encodedBool)
35+
36+
super.init()
3037
}
3138

3239
open func encode(with aCoder: NSCoder) {
33-
NSUnimplemented()
40+
guard aCoder.allowsKeyedCoding else {
41+
preconditionFailure("Unkeyed coding is unsupported.")
42+
}
43+
44+
//TODO: store kind key for .boolean, .format, .metadataQuery
45+
46+
switch self.kind {
47+
case .boolean(let value):
48+
aCoder.encode(value, forKey: "NS.boolean.value")
49+
case .block:
50+
preconditionFailure("NSBlockPredicate cannot be encoded or decoded.")
51+
case .format:
52+
NSUnimplemented()
53+
case .metadataQuery:
54+
NSUnimplemented()
55+
}
3456
}
3557

3658
open override func copy() -> Any {
3759
return copy(with: nil)
3860
}
3961

4062
open func copy(with zone: NSZone? = nil) -> Any {
41-
NSUnimplemented()
63+
switch self.kind {
64+
case .boolean(let value):
65+
return NSPredicate(value: value)
66+
case .block(let block):
67+
return NSPredicate(block: block)
68+
case .format:
69+
NSUnimplemented()
70+
case .metadataQuery:
71+
NSUnimplemented()
72+
}
73+
}
74+
75+
open override func isEqual(_ object: Any?) -> Bool {
76+
if let other = object as? NSPredicate {
77+
if other === self {
78+
return true
79+
} else {
80+
switch (other.kind, self.kind) {
81+
case (.boolean(let otherBool), .boolean(let selfBool)):
82+
return otherBool == selfBool
83+
case (.format, .format):
84+
NSUnimplemented()
85+
case (.metadataQuery, .metadataQuery):
86+
NSUnimplemented()
87+
default:
88+
// NSBlockPredicate returns false even for copy
89+
return false
90+
}
91+
}
92+
}
93+
94+
return false
4295
}
4396

4497
// Parse predicateFormat and return an appropriate predicate
@@ -58,7 +111,21 @@ open class NSPredicate : NSObject, NSSecureCoding, NSCopying {
58111
super.init()
59112
}
60113

61-
open var predicateFormat: String { NSUnimplemented() } // returns the format string of the predicate
114+
open var predicateFormat: String {
115+
switch self.kind {
116+
case .boolean(let value):
117+
return value ? "TRUEPREDICATE" : "FALSEPREDICATE"
118+
case .block:
119+
// TODO: Bring NSBlockPredicate's predicateFormat to macOS's Foundation version
120+
// let address = unsafeBitCast(block, to: Int.self)
121+
// return String(format:"BLOCKPREDICATE(%2X)", address)
122+
return "BLOCKPREDICATE"
123+
case .format:
124+
NSUnimplemented()
125+
case .metadataQuery:
126+
NSUnimplemented()
127+
}
128+
}
62129

63130
open func withSubstitutionVariables(_ variables: [String : Any]) -> Self { NSUnimplemented() } // substitute constant values for variables
64131

@@ -76,6 +143,10 @@ open class NSPredicate : NSObject, NSSecureCoding, NSCopying {
76143
return value
77144
case let .block(block):
78145
return block(object, bindings)
146+
case .format:
147+
NSUnimplemented()
148+
case .metadataQuery:
149+
NSUnimplemented()
79150
}
80151
} // single pass evaluation substituting variables from the bindings dictionary for any variable expressions encountered
81152

TestFoundation/TestNSPredicate.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class TestNSPredicate: XCTestCase {
2727
("test_filterNSMutableSet", test_filterNSMutableSet),
2828
("test_filterNSOrderedSet", test_filterNSOrderedSet),
2929
("test_filterNSMutableOrderedSet", test_filterNSMutableOrderedSet),
30+
("test_NSCoding", test_NSCoding),
31+
("test_copy", test_copy),
3032
]
3133
}
3234

@@ -94,4 +96,15 @@ class TestNSPredicate: XCTestCase {
9496
expectedOrderedSet.addObjects(from: expectedArray)
9597
XCTAssertEqual(expectedOrderedSet, orderedSet)
9698
}
99+
100+
func test_NSCoding() {
101+
let predicateA = NSPredicate(value: true)
102+
let predicateB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateA)) as! NSPredicate
103+
XCTAssertEqual(predicateA, predicateB, "Archived then unarchived uuid must be equal.")
104+
}
105+
106+
func test_copy() {
107+
let predicate = NSPredicate(value: true)
108+
XCTAssert(predicate.isEqual(predicate.copy()))
109+
}
97110
}

0 commit comments

Comments
 (0)