-
Notifications
You must be signed in to change notification settings - Fork 196
Expand file tree
/
Copy pathManaged.swift
More file actions
130 lines (101 loc) · 4.62 KB
/
Managed.swift
File metadata and controls
130 lines (101 loc) · 4.62 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
//
// ManagedObject.swift
// Moody
//
// Created by Florian on 29/05/15.
// Copyright (c) 2015 objc.io. All rights reserved.
//
import CoreData
public protocol Managed: class, NSFetchRequestResult {
static var entity: NSEntityDescription { get }
static var entityName: String { get }
static var defaultSortDescriptors: [NSSortDescriptor] { get }
static var defaultPredicate: NSPredicate { get }
var managedObjectContext: NSManagedObjectContext? { get }
}
public protocol DefaultManaged: Managed {}
extension DefaultManaged {
public static var defaultPredicate: NSPredicate { return NSPredicate(value: true) }
}
extension Managed {
public static var defaultSortDescriptors: [NSSortDescriptor] { return [] }
public static var defaultPredicate: NSPredicate { return NSPredicate(value: true) }
public static var sortedFetchRequest: NSFetchRequest<Self> {
let request = NSFetchRequest<Self>(entityName: entityName)
request.sortDescriptors = defaultSortDescriptors
request.predicate = defaultPredicate
return request
}
public static func sortedFetchRequest(with predicate: NSPredicate) -> NSFetchRequest<Self> {
let request = sortedFetchRequest
guard let existingPredicate = request.predicate else { fatalError("must have predicate") }
request.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [existingPredicate, predicate])
return request
}
public static func predicate(format: String, _ args: CVarArg...) -> NSPredicate {
let p = withVaList(args) { NSPredicate(format: format, arguments: $0) }
return predicate(p)
}
public static func predicate(_ predicate: NSPredicate) -> NSPredicate {
return NSCompoundPredicate(andPredicateWithSubpredicates: [defaultPredicate, predicate])
}
}
extension Managed where Self: NSManagedObject {
public static var entity: NSEntityDescription { return entity() }
public static var entityName: String { return entity.name! }
public static func findOrCreate(in context: NSManagedObjectContext, matching predicate: NSPredicate, configure: (Self) -> ()) -> Self {
guard let object = findOrFetch(in: context, matching: predicate) else {
let newObject: Self = context.insertObject()
configure(newObject)
return newObject
}
return object
}
public static func findOrFetch(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? {
guard let object = materializedObject(in: context, matching: predicate) else {
return fetch(in: context) { request in
request.predicate = predicate
request.returnsObjectsAsFaults = false
request.fetchLimit = 1
}.first
}
return object
}
public static func fetch(in context: NSManagedObjectContext, configurationBlock: (NSFetchRequest<Self>) -> () = { _ in }) -> [Self] {
let request = NSFetchRequest<Self>(entityName: Self.entityName)
configurationBlock(request)
return try! context.fetch(request)
}
public static func count(in context: NSManagedObjectContext, configure: (NSFetchRequest<Self>) -> () = { _ in }) -> Int {
let request = NSFetchRequest<Self>(entityName: entityName)
configure(request)
return try! context.count(for: request)
}
public static func materializedObject(in context: NSManagedObjectContext, matching predicate: NSPredicate) -> Self? {
for object in context.registeredObjects where !object.isFault {
guard let result = object as? Self, predicate.evaluate(with: result) else { continue }
return result
}
return nil
}
}
extension Managed where Self: NSManagedObject {
public static func fetchSingleObject(in context: NSManagedObjectContext, cacheKey: String, configure: (NSFetchRequest<Self>) -> ()) -> Self? {
if let cached = context.object(forSingleObjectCacheKey: cacheKey) as? Self { return cached
}
let result = fetchSingleObject(in: context, configure: configure)
context.set(result, forSingleObjectCacheKey: cacheKey)
return result
}
fileprivate static func fetchSingleObject(in context: NSManagedObjectContext, configure: (NSFetchRequest<Self>) -> ()) -> Self? {
let result = fetch(in: context) { request in
configure(request)
request.fetchLimit = 2
}
switch result.count {
case 0: return nil
case 1: return result[0]
default: fatalError("Returned multiple objects, expected max 1")
}
}
}