-
Notifications
You must be signed in to change notification settings - Fork 198
/
Copy pathContents.swift
116 lines (93 loc) · 3.9 KB
/
Contents.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
//: # Predicates
//:
//: ## Using `NSPredicate` with Core Data.
//:
//: Predicates let us filter objects. We can either specify a predicate on a fetch request or match objects directly.
//:
//:
//:
//: ### Book
//:
//: This Playround is part of objc.io’s [Core Data Book](https://www.objc.io/books/core-data/).
//: ### Setup
//:
//: This Playground uses `Person` and `City` classes and corresponding entities to show how predicates can be used.
//: These are all defined in the `PersonAndCity.swift` file. Additionally this Playground uses some of the *shared code* used throughout the book.
//:
//: We create a persistent container with a simple model. And we use the `viewContext` for all samples.
import Foundation
import CoreData
let container = citiesAndPeopleModel().createContainerWithLoadedStores()
let context = container.viewContext
createCitiesAndPeople(in: context)
//: The following implements *in-memory* filtering (of `Person` and `City`).
//: This is usually **not** what you want to do, but we use it in this Playground
//: to illustrate some predicate related aspects.
//: ## Introduction
//:
//: ### Direct Evaluation
//: The `evaluateWithObject(_:)` method lets us match an object directly.
do {
let request = Person.sortedFetchRequest
request.fetchLimit = 1
let person = try! context.fetch(request).first!
let predicate = NSPredicate(format: "age == 32")
if predicate.evaluate(with: person) {
print("\(person.name) is 32 years old")
} else {
print("\(person.name) is not 32 years")
}
}
//: ### Fetch Request
//: Fetch requests have a `predicate` property that we can set an `NSPredicate` on to limit the result to matching objects.
do {
let request = NSFetchRequest<Person>()
request.entity = Person.entity()
request.fetchLimit = 1
request.predicate = NSPredicate(format: "age == 32")
let result = try! context.fetch(request)
if let person = result.first {
print("\(person.name) is \(person.age) years old")
}
}
//: ## Simple Examples
//:
//: When creating a predicate,
//: the most straightforward approach is to use a format string.
do {
let predicate = NSPredicate(format: "age == 32")
let names = context.fetchPeople(matching: predicate).map{ $0.personNameAndAge }
names
}
//: But we should not hardcode *keys* / *attribute names* inside format strings. Instead it is better to use the `%K` format specifier and pass the key (or key path) as an argument with `#keyPath()`. With this the compiler help us to avoid typos in attribute names. And it makes easier for us to later change attribute names.
do {
let predicate = NSPredicate(format: "%K == 32", #keyPath(Person.age))
let names = context.fetchPeople(matching: predicate).map{ $0.personNameAndAge }
names
}
//: Likewise constant values can be moved outside the format string itself.
do {
let predicate = NSPredicate(format: "%K < %ld", #keyPath(Person.age), 32)
let names = context.fetchPeople(matching: predicate).map{ $0.personNameAndAge }
}
//: There are various different comparison operators.
do {
let predicateA = NSPredicate(format: "%K <= 30", #keyPath(Person.age))
let predicateB = NSPredicate(format: "%K > 30", #keyPath(Person.age))
let predicateC = NSPredicate(format: "%K != 24", #keyPath(Person.age))
let namesA = context.fetchPeople(matching: predicateA).map{ $0.personNameAndAge }
namesA
let namesB = context.fetchPeople(matching: predicateB).map{ $0.personNameAndAge }
namesB
let namesC = context.fetchPeople(matching: predicateC).map{ $0.personNameAndAge }
namesC
}
//: ## Matching Multiple Values
//: We can match multiple values with the `IN` operator.
do {
let primeNumbers = [13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
let predicate = NSPredicate(format: "%K IN %@", #keyPath(Person.age), primeNumbers)
let names = context.fetchPeople(matching: predicate).map{ $0.personNameAndAge }
names
}
//: [Next](@next)