Skip to content

Commit 8ef3b28

Browse files
committed
Merge branch 'develop'
2 parents a2149db + 6aaf23b commit 8ef3b28

File tree

10 files changed

+139
-21
lines changed

10 files changed

+139
-21
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Adheres to [Semantic Versioning](http://semver.org/).
1919
* Tapping a local attachment does not show the attachment
2020
* Distance is not being calculated correctly when navigation lines are updated
2121
* Add more informative message when an attachment fails to open
22+
* Significantly improved the speed of the initial observation fetch
2223

2324
## 4.0.1
2425

MAGE.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3804,7 +3804,7 @@
38043804
CLANG_CXX_LIBRARY = "compiler-default";
38053805
CLANG_ENABLE_MODULES = YES;
38063806
CODE_SIGN_ENTITLEMENTS = MAGE/MAGE.entitlements;
3807-
CODE_SIGN_IDENTITY = "Apple Development";
3807+
CODE_SIGN_IDENTITY = "iPhone Developer";
38083808
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
38093809
CODE_SIGN_STYLE = Manual;
38103810
DEVELOPMENT_TEAM = ZL8G5D9G2H;
@@ -3838,7 +3838,7 @@
38383838
CLANG_CXX_LIBRARY = "compiler-default";
38393839
CLANG_ENABLE_MODULES = YES;
38403840
CODE_SIGN_ENTITLEMENTS = MAGE/MAGE.entitlements;
3841-
CODE_SIGN_IDENTITY = "Apple Development";
3841+
CODE_SIGN_IDENTITY = "iPhone Developer";
38423842
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
38433843
CODE_SIGN_STYLE = Manual;
38443844
DEVELOPMENT_TEAM = ZL8G5D9G2H;

Mage/CoreData/Event.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,14 @@ import CoreData
1717
}
1818
let url = "\(baseURL.absoluteURL)/api/events";
1919
let manager = MageSessionManager.shared();
20+
let methodStart = Date()
21+
NSLog("TIMING Fetching Events @ \(methodStart)")
22+
2023
let task = manager?.get_TASK(url, parameters: nil, progress: nil, success: { task, responseObject in
24+
NSLog("TIMING Fetched Events. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
25+
26+
let saveStart = Date()
27+
NSLog("TIMING Saving Events @ \(saveStart)")
2128
MagicalRecord.save { localContext in
2229
let localUser = User.fetchCurrentUser(context: localContext);
2330
var eventsReturned: [NSNumber] = []
@@ -48,6 +55,8 @@ import CoreData
4855
}
4956
Event.mr_deleteAll(matching: NSPredicate(format: "NOT (\(EventKey.remoteId.key) IN %@)", eventsReturned), in: localContext);
5057
} completion: { contextDidSave, error in
58+
NSLog("TIMING Saved Events. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
59+
5160
NotificationCenter.default.post(name: .MAGEEventsFetched, object:nil)
5261

5362
if let error = error {

Mage/CoreData/Feed.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,14 @@ import CoreData
9494
var feedRemoteIds: [String] = [];
9595
let url = "\(baseURL.absoluteURL)/api/events/\(eventId)/feeds";
9696
let manager = MageSessionManager.shared();
97+
let methodStart = Date()
98+
NSLog("TIMING Fetching Feeds @ \(methodStart)")
9799
let task = manager?.get_TASK(url, parameters: nil, progress: nil,
98100
success: { task, responseObject in
101+
NSLog("TIMING Fetched Feeds. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
102+
103+
let saveStart = Date()
104+
NSLog("TIMING Saving Feeds @ \(saveStart)")
99105
MagicalRecord.save({ localContext in
100106
if let feedsJson = responseObject as? [[AnyHashable : Any]] {
101107
feedRemoteIds = Feed.populateFeeds(feeds: feedsJson, eventId: eventId, context: localContext);
@@ -105,6 +111,8 @@ import CoreData
105111
Feed.mr_deleteAll(matching: NSPredicate(format: "(NOT (\(FeedKey.remoteId.key) IN %@)) AND \(FeedKey.eventId.key) == %@", feedRemoteIds, eventId), in: localContext)
106112
}
107113
}, completion: { contextDidSave, error in
114+
NSLog("TIMING Saved Feeds. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
115+
108116
if let error = error {
109117
if let failure = failure {
110118
failure(error);
@@ -127,12 +135,19 @@ import CoreData
127135
}
128136
let url = "\(baseURL.absoluteURL)/api/events/\(eventId)/feeds/\(feedId)/content";
129137
let manager = MageSessionManager.shared();
138+
let methodStart = Date()
139+
NSLog("TIMING Fetching Feed Items /api/events/\(eventId)/feeds/\(feedId)/content @ \(methodStart)")
130140
let task = manager?.post_TASK(url, parameters: nil, progress: nil, success: { task, responseObject in
141+
NSLog("TIMING Fetched Feed Items /api/events/\(eventId)/feeds/\(feedId)/content. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
142+
143+
let saveStart = Date()
144+
NSLog("TIMING Saving Feed Items /api/events/\(eventId)/feeds/\(feedId)/content @ \(saveStart)")
131145
MagicalRecord.save { localContext in
132146
if let json = responseObject as? [AnyHashable : Any], let items = json[FeedKey.items.key] as? [AnyHashable : Any], let features = items[FeedKey.features.key] as? [[AnyHashable : Any]] {
133147
Feed.populateFeedItems(feedItems: features, feedId: feedId, eventId: eventId, context: localContext);
134148
}
135149
} completion: { contextDidSave, error in
150+
NSLog("TIMING Saved Feed Items. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
136151
if let error = error {
137152
if let failure = failure {
138153
failure(task, error);

Mage/CoreData/Form.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ import CoreData
136136
return nil
137137
}
138138

139+
static func getFieldByNameFromJSONFields(json: [[String: AnyHashable]], name: String) -> [String: AnyHashable]? {
140+
return json.first { field in
141+
field[FieldKey.name.key] as? String == name
142+
}
143+
}
144+
139145
static func getDocumentsDirectory() -> String {
140146
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
141147
let documentsDirectory = paths[0]
@@ -153,12 +159,17 @@ import CoreData
153159
let folderToUnzipTo = "\(getDocumentsDirectory())/events/icons-\(eventId)"
154160

155161
do {
162+
let methodStart = Date()
163+
NSLog("TIMING Fetching Form for event \(eventId) @ \(methodStart)")
164+
156165
guard let request = try manager?.requestSerializer.request(withMethod: "GET", urlString: url, parameters: nil) else {
157166
return nil;
158167
}
159168
let task = manager?.downloadTask(with: request as URLRequest, progress: nil, destination: { targetPath, response in
160169
return URL(fileURLWithPath: stringPath);
161170
}, completionHandler: { response, filePath, error in
171+
NSLog("TIMING Fetched Form for event \(eventId). Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
172+
162173
if let error = error {
163174
NSLog("Error pulling icons and form \(error)")
164175
failure?(error);

Mage/CoreData/Location.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ import MagicalRecord
115115
parameters["startDate"] = ISO8601DateFormatter.string(from: lastLocationDate, timeZone: TimeZone(secondsFromGMT: 0)!, formatOptions: [.withDashSeparatorInDate, .withFullDate, .withFractionalSeconds, .withTime, .withColonSeparatorInTime, .withTimeZone])
116116
}
117117
let manager = MageSessionManager.shared();
118+
let methodStart = Date()
119+
NSLog("TIMING Fetching Locations /api/events/\(currentEventId)/locations/users @ \(methodStart)")
118120
let task = manager?.get_TASK(url, parameters: parameters, progress: nil, success: { task, responseObject in
121+
NSLog("TIMING Fetched Locations /api/events/\(currentEventId)/locations/users. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
119122
guard let allUserLocations = responseObject as? [[AnyHashable : Any]] else {
120123
success?(task, nil);
121124
return;
@@ -126,6 +129,9 @@ import MagicalRecord
126129
success?(task, responseObject)
127130
return;
128131
}
132+
133+
let saveStart = Date()
134+
NSLog("TIMING Saving Locations /api/events/\(currentEventId)/locations/users @ \(saveStart)")
129135
MagicalRecord.save { localContext in
130136
let currentUser = User.fetchCurrentUser(context: localContext);
131137

@@ -213,6 +219,8 @@ import MagicalRecord
213219
User.operationToFetchUsers(success: nil, failure: nil);
214220
}
215221
} completion: { contextDidSave, error in
222+
NSLog("TIMING Saved Locations /api/events/\(currentEventId)/locations/users. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
223+
216224
if let error = error {
217225
failure?(task, error);
218226
} else if let success = success {

Mage/CoreData/Observation.swift

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,10 @@ enum State: Int, CustomStringConvertible {
155155
}
156156

157157
let manager = MageSessionManager.shared();
158+
let methodStart = Date()
159+
NSLog("TIMING Fetching Observations for event \(currentEventId) @ \(methodStart)")
158160
let task = manager?.get_TASK(url, parameters: parameters, progress: nil, success: { task, responseObject in
161+
NSLog("TIMING Fetched Observations for event \(currentEventId). Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
159162
guard let features = responseObject as? [[AnyHashable : Any]] else {
160163
success?(task, nil);
161164
return;
@@ -167,47 +170,72 @@ enum State: Int, CustomStringConvertible {
167170
return;
168171
}
169172

173+
let saveStart = Date()
174+
NSLog("TIMING Saving Observations for event \(currentEventId) @ \(saveStart)")
170175
let rootSavingContext = NSManagedObjectContext.mr_rootSaving();
171176
let localContext = NSManagedObjectContext.mr_context(withParent: rootSavingContext);
172177
localContext.perform {
178+
NSLog("TIMING There are \(features.count) features to save, chunking into groups of 250")
173179
localContext.mr_setWorkingName(#function)
180+
174181
var chunks = features.chunked(into: 250);
175182
var newObservationCount = 0;
176183
var observationToNotifyAbout: Observation?;
184+
var eventFormDictionary: [NSNumber: [[String: AnyHashable]]] = [:]
185+
if let event = Event.getEvent(eventId: currentEventId, context: localContext), let eventForms = event.forms {
186+
for eventForm in eventForms {
187+
if let formId = eventForm.formId, let json = eventForm.json?.json {
188+
eventFormDictionary[formId] = json[FormKey.fields.key] as? [[String: AnyHashable]]
189+
}
190+
}
191+
}
192+
localContext.reset();
193+
NSLog("TIMING we have \(chunks.count) groups to save")
177194
while (chunks.count > 0) {
178195
autoreleasepool {
179196
guard let features = chunks.last else {
180197
return;
181198
}
182199
chunks.removeLast();
183-
200+
let createObservationsDate = Date()
201+
NSLog("TIMING creating \(features.count) observations for chunk \(chunks.count)")
202+
184203
for observation in features {
185-
if let newObservation = Observation.create(feature: observation, context: localContext) {
204+
if let newObservation = Observation.create(feature: observation, eventForms: eventFormDictionary, context: localContext) {
186205
newObservationCount = newObservationCount + 1;
187206
if (!initial) {
188207
observationToNotifyAbout = newObservation;
189208
}
190209
}
191210
}
192-
print("Saved \(features.count) observations")
211+
NSLog("TIMING created \(features.count) observations for chunk \(chunks.count) Elapsed: \(createObservationsDate.timeIntervalSinceNow) seconds")
193212
}
194213

195214
// only save once per chunk
215+
let localSaveDate = Date()
196216
do {
217+
NSLog("TIMING saving \(features.count) observations on local context")
197218
try localContext.save()
198219
} catch {
199220
print("Error saving observations: \(error)")
200221
}
222+
NSLog("TIMING saved \(features.count) observations on local context. Elapsed \(localSaveDate.timeIntervalSinceNow) seconds")
201223

202224
rootSavingContext.perform {
225+
let rootSaveDate = Date()
226+
203227
do {
228+
NSLog("TIMING saving \(features.count) observations on root context")
204229
try rootSavingContext.save()
205230
} catch {
206231
print("Error saving observations: \(error)")
207232
}
233+
NSLog("TIMING saved \(features.count) observations on root context. Elapsed \(rootSaveDate.timeIntervalSinceNow) seconds")
234+
208235
}
209236

210237
localContext.reset();
238+
NSLog("TIMING reset the local context for chunk \(chunks.count)")
211239
NSLog("Saved chunk \(chunks.count)")
212240
}
213241

@@ -218,6 +246,7 @@ enum State: Int, CustomStringConvertible {
218246
NotificationRequester.observationPulled(observationToNotifyAbout);
219247
}
220248

249+
NSLog("TIMING Saved Observations for event \(currentEventId). Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
221250
DispatchQueue.main.async {
222251
success?(task, responseObject);
223252
}
@@ -550,12 +579,14 @@ enum State: Int, CustomStringConvertible {
550579
}
551580

552581
@discardableResult
553-
@objc public static func create(feature: [AnyHashable : Any], context:NSManagedObjectContext) -> Observation? {
582+
@objc public static func create(feature: [AnyHashable : Any], eventForms: [NSNumber: [[String: AnyHashable]]]? = nil, context:NSManagedObjectContext) -> Observation? {
554583
var newObservation: Observation? = nil;
555584
let remoteId = Observation.idFromJson(json: feature);
556585

557586
let state = Observation.stateFromJson(json: feature);
558587

588+
// NSLog("TIMING create the observation \(remoteId)")
589+
559590
if let remoteId = remoteId, let existingObservation = Observation.mr_findFirst(byAttribute: ObservationKey.remoteId.key, withValue: remoteId, in: context) {
560591
// if the observation is archived, delete it
561592
if state == .Archive {
@@ -574,7 +605,7 @@ enum State: Int, CustomStringConvertible {
574605
}
575606
}
576607

577-
existingObservation.populate(json: feature);
608+
existingObservation.populate(json: feature, eventForms: eventForms);
578609
if let userId = existingObservation.userId {
579610
if let user = User.mr_findFirst(byAttribute: ObservationKey.remoteId.key, withValue: userId, in: context) {
580611
existingObservation.user = user
@@ -662,7 +693,7 @@ enum State: Int, CustomStringConvertible {
662693
if state != .Archive {
663694
// if the observation doesn't exist, insert it
664695
if let observation = Observation.mr_createEntity(in: context) {
665-
observation.populate(json: feature);
696+
observation.populate(json: feature, eventForms: eventForms);
666697
if let userId = observation.userId {
667698
if let user = User.mr_findFirst(byAttribute: UserKey.remoteId.key, withValue: userId, in: context) {
668699
observation.user = user
@@ -752,15 +783,15 @@ enum State: Int, CustomStringConvertible {
752783
}
753784

754785
@discardableResult
755-
@objc public func populate(json: [AnyHashable : Any]) -> Observation {
786+
@objc public func populate(json: [AnyHashable : Any], eventForms: [NSNumber: [[String: AnyHashable]]]? = nil) -> Observation {
756787
self.eventId = json[ObservationKey.eventId.key] as? NSNumber
757788
self.remoteId = Observation.idFromJson(json: json);
758789
self.userId = json[ObservationKey.userId.key] as? String
759790
self.deviceId = json[ObservationKey.deviceId.key] as? String
760791
self.dirty = false
761792

762793
if let properties = json[ObservationKey.properties.key] as? [String : Any] {
763-
self.properties = self.generateProperties(propertyJson: properties);
794+
self.properties = self.generateProperties(propertyJson: properties, eventForms: eventForms);
764795
}
765796

766797
if let lastModified = json[ObservationKey.lastModified.key] as? String {
@@ -785,7 +816,7 @@ enum State: Int, CustomStringConvertible {
785816
return self;
786817
}
787818

788-
func generateProperties(propertyJson: [String : Any]) -> [AnyHashable : Any] {
819+
func generateProperties(propertyJson: [String : Any], eventForms: [NSNumber: [[String: AnyHashable]]]? = nil) -> [AnyHashable : Any] {
789820
var parsedProperties: [String : Any] = [:]
790821

791822
if self.event == nil {
@@ -798,19 +829,29 @@ enum State: Int, CustomStringConvertible {
798829
if let formsProperties = value as? [[String : Any]] {
799830
for formProperties in formsProperties {
800831
var parsedFormProperties:[String:Any] = formProperties;
801-
if let formId = formProperties[EventKey.formId.key] as? NSNumber, let managedObjectContext = managedObjectContext, let form : Form = Form.mr_findFirst(byAttribute: "formId", withValue: formId, in: managedObjectContext) {
802-
for (formKey, value) in formProperties {
803-
if let field = form.getFieldByName(name: formKey) {
804-
if let type = field[FieldKey.type.key] as? String, type == FieldType.geometry.key {
805-
if let value = value as? [String: Any] {
806-
let geometry = GeometryDeserializer.parseGeometry(json: value)
807-
parsedFormProperties[formKey] = geometry;
832+
833+
if let formId = formProperties[EventKey.formId.key] as? NSNumber {
834+
var formFields: [[String: AnyHashable]]? = nil
835+
if let eventForms = eventForms {
836+
formFields = eventForms[formId]
837+
} else if let managedObjectContext = managedObjectContext, let fetchedForm : Form = Form.mr_findFirst(byAttribute: "formId", withValue: formId, in: managedObjectContext) {
838+
formFields = fetchedForm.json?.json?[FormKey.fields.key] as? [[String: AnyHashable]]
839+
}
840+
841+
if let formFields = formFields {
842+
for (formKey, value) in formProperties {
843+
if let field = Form.getFieldByNameFromJSONFields(json: formFields, name: formKey) {
844+
if let type = field[FieldKey.type.key] as? String, type == FieldType.geometry.key {
845+
if let value = value as? [String: Any] {
846+
let geometry = GeometryDeserializer.parseGeometry(json: value)
847+
parsedFormProperties[formKey] = geometry;
848+
}
808849
}
809850
}
810851
}
811852
}
853+
forms.append(parsedFormProperties);
812854
}
813-
forms.append(parsedFormProperties);
814855
}
815856
}
816857
parsedProperties[ObservationKey.forms.key] = forms;

0 commit comments

Comments
 (0)