Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbarela committed Jul 27, 2022
2 parents a2149db + 6aaf23b commit 8ef3b28
Show file tree
Hide file tree
Showing 10 changed files with 139 additions and 21 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Adheres to [Semantic Versioning](http://semver.org/).
* Tapping a local attachment does not show the attachment
* Distance is not being calculated correctly when navigation lines are updated
* Add more informative message when an attachment fails to open
* Significantly improved the speed of the initial observation fetch

## 4.0.1

Expand Down
4 changes: 2 additions & 2 deletions MAGE.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3804,7 +3804,7 @@
CLANG_CXX_LIBRARY = "compiler-default";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = MAGE/MAGE.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = ZL8G5D9G2H;
Expand Down Expand Up @@ -3838,7 +3838,7 @@
CLANG_CXX_LIBRARY = "compiler-default";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = MAGE/MAGE.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
CODE_SIGN_STYLE = Manual;
DEVELOPMENT_TEAM = ZL8G5D9G2H;
Expand Down
9 changes: 9 additions & 0 deletions Mage/CoreData/Event.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,14 @@ import CoreData
}
let url = "\(baseURL.absoluteURL)/api/events";
let manager = MageSessionManager.shared();
let methodStart = Date()
NSLog("TIMING Fetching Events @ \(methodStart)")

let task = manager?.get_TASK(url, parameters: nil, progress: nil, success: { task, responseObject in
NSLog("TIMING Fetched Events. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")

let saveStart = Date()
NSLog("TIMING Saving Events @ \(saveStart)")
MagicalRecord.save { localContext in
let localUser = User.fetchCurrentUser(context: localContext);
var eventsReturned: [NSNumber] = []
Expand Down Expand Up @@ -48,6 +55,8 @@ import CoreData
}
Event.mr_deleteAll(matching: NSPredicate(format: "NOT (\(EventKey.remoteId.key) IN %@)", eventsReturned), in: localContext);
} completion: { contextDidSave, error in
NSLog("TIMING Saved Events. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")

NotificationCenter.default.post(name: .MAGEEventsFetched, object:nil)

if let error = error {
Expand Down
15 changes: 15 additions & 0 deletions Mage/CoreData/Feed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,14 @@ import CoreData
var feedRemoteIds: [String] = [];
let url = "\(baseURL.absoluteURL)/api/events/\(eventId)/feeds";
let manager = MageSessionManager.shared();
let methodStart = Date()
NSLog("TIMING Fetching Feeds @ \(methodStart)")
let task = manager?.get_TASK(url, parameters: nil, progress: nil,
success: { task, responseObject in
NSLog("TIMING Fetched Feeds. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")

let saveStart = Date()
NSLog("TIMING Saving Feeds @ \(saveStart)")
MagicalRecord.save({ localContext in
if let feedsJson = responseObject as? [[AnyHashable : Any]] {
feedRemoteIds = Feed.populateFeeds(feeds: feedsJson, eventId: eventId, context: localContext);
Expand All @@ -105,6 +111,8 @@ import CoreData
Feed.mr_deleteAll(matching: NSPredicate(format: "(NOT (\(FeedKey.remoteId.key) IN %@)) AND \(FeedKey.eventId.key) == %@", feedRemoteIds, eventId), in: localContext)
}
}, completion: { contextDidSave, error in
NSLog("TIMING Saved Feeds. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")

if let error = error {
if let failure = failure {
failure(error);
Expand All @@ -127,12 +135,19 @@ import CoreData
}
let url = "\(baseURL.absoluteURL)/api/events/\(eventId)/feeds/\(feedId)/content";
let manager = MageSessionManager.shared();
let methodStart = Date()
NSLog("TIMING Fetching Feed Items /api/events/\(eventId)/feeds/\(feedId)/content @ \(methodStart)")
let task = manager?.post_TASK(url, parameters: nil, progress: nil, success: { task, responseObject in
NSLog("TIMING Fetched Feed Items /api/events/\(eventId)/feeds/\(feedId)/content. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")

let saveStart = Date()
NSLog("TIMING Saving Feed Items /api/events/\(eventId)/feeds/\(feedId)/content @ \(saveStart)")
MagicalRecord.save { localContext in
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]] {
Feed.populateFeedItems(feedItems: features, feedId: feedId, eventId: eventId, context: localContext);
}
} completion: { contextDidSave, error in
NSLog("TIMING Saved Feed Items. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")
if let error = error {
if let failure = failure {
failure(task, error);
Expand Down
11 changes: 11 additions & 0 deletions Mage/CoreData/Form.swift
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@ import CoreData
return nil
}

static func getFieldByNameFromJSONFields(json: [[String: AnyHashable]], name: String) -> [String: AnyHashable]? {
return json.first { field in
field[FieldKey.name.key] as? String == name
}
}

static func getDocumentsDirectory() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
let documentsDirectory = paths[0]
Expand All @@ -153,12 +159,17 @@ import CoreData
let folderToUnzipTo = "\(getDocumentsDirectory())/events/icons-\(eventId)"

do {
let methodStart = Date()
NSLog("TIMING Fetching Form for event \(eventId) @ \(methodStart)")

guard let request = try manager?.requestSerializer.request(withMethod: "GET", urlString: url, parameters: nil) else {
return nil;
}
let task = manager?.downloadTask(with: request as URLRequest, progress: nil, destination: { targetPath, response in
return URL(fileURLWithPath: stringPath);
}, completionHandler: { response, filePath, error in
NSLog("TIMING Fetched Form for event \(eventId). Elapsed: \(methodStart.timeIntervalSinceNow) seconds")

if let error = error {
NSLog("Error pulling icons and form \(error)")
failure?(error);
Expand Down
8 changes: 8 additions & 0 deletions Mage/CoreData/Location.swift
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ import MagicalRecord
parameters["startDate"] = ISO8601DateFormatter.string(from: lastLocationDate, timeZone: TimeZone(secondsFromGMT: 0)!, formatOptions: [.withDashSeparatorInDate, .withFullDate, .withFractionalSeconds, .withTime, .withColonSeparatorInTime, .withTimeZone])
}
let manager = MageSessionManager.shared();
let methodStart = Date()
NSLog("TIMING Fetching Locations /api/events/\(currentEventId)/locations/users @ \(methodStart)")
let task = manager?.get_TASK(url, parameters: parameters, progress: nil, success: { task, responseObject in
NSLog("TIMING Fetched Locations /api/events/\(currentEventId)/locations/users. Elapsed: \(methodStart.timeIntervalSinceNow) seconds")
guard let allUserLocations = responseObject as? [[AnyHashable : Any]] else {
success?(task, nil);
return;
Expand All @@ -126,6 +129,9 @@ import MagicalRecord
success?(task, responseObject)
return;
}

let saveStart = Date()
NSLog("TIMING Saving Locations /api/events/\(currentEventId)/locations/users @ \(saveStart)")
MagicalRecord.save { localContext in
let currentUser = User.fetchCurrentUser(context: localContext);

Expand Down Expand Up @@ -213,6 +219,8 @@ import MagicalRecord
User.operationToFetchUsers(success: nil, failure: nil);
}
} completion: { contextDidSave, error in
NSLog("TIMING Saved Locations /api/events/\(currentEventId)/locations/users. Elapsed: \(saveStart.timeIntervalSinceNow) seconds")

if let error = error {
failure?(task, error);
} else if let success = success {
Expand Down
75 changes: 58 additions & 17 deletions Mage/CoreData/Observation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,10 @@ enum State: Int, CustomStringConvertible {
}

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

let saveStart = Date()
NSLog("TIMING Saving Observations for event \(currentEventId) @ \(saveStart)")
let rootSavingContext = NSManagedObjectContext.mr_rootSaving();
let localContext = NSManagedObjectContext.mr_context(withParent: rootSavingContext);
localContext.perform {
NSLog("TIMING There are \(features.count) features to save, chunking into groups of 250")
localContext.mr_setWorkingName(#function)

var chunks = features.chunked(into: 250);
var newObservationCount = 0;
var observationToNotifyAbout: Observation?;
var eventFormDictionary: [NSNumber: [[String: AnyHashable]]] = [:]
if let event = Event.getEvent(eventId: currentEventId, context: localContext), let eventForms = event.forms {
for eventForm in eventForms {
if let formId = eventForm.formId, let json = eventForm.json?.json {
eventFormDictionary[formId] = json[FormKey.fields.key] as? [[String: AnyHashable]]
}
}
}
localContext.reset();
NSLog("TIMING we have \(chunks.count) groups to save")
while (chunks.count > 0) {
autoreleasepool {
guard let features = chunks.last else {
return;
}
chunks.removeLast();

let createObservationsDate = Date()
NSLog("TIMING creating \(features.count) observations for chunk \(chunks.count)")

for observation in features {
if let newObservation = Observation.create(feature: observation, context: localContext) {
if let newObservation = Observation.create(feature: observation, eventForms: eventFormDictionary, context: localContext) {
newObservationCount = newObservationCount + 1;
if (!initial) {
observationToNotifyAbout = newObservation;
}
}
}
print("Saved \(features.count) observations")
NSLog("TIMING created \(features.count) observations for chunk \(chunks.count) Elapsed: \(createObservationsDate.timeIntervalSinceNow) seconds")
}

// only save once per chunk
let localSaveDate = Date()
do {
NSLog("TIMING saving \(features.count) observations on local context")
try localContext.save()
} catch {
print("Error saving observations: \(error)")
}
NSLog("TIMING saved \(features.count) observations on local context. Elapsed \(localSaveDate.timeIntervalSinceNow) seconds")

rootSavingContext.perform {
let rootSaveDate = Date()

do {
NSLog("TIMING saving \(features.count) observations on root context")
try rootSavingContext.save()
} catch {
print("Error saving observations: \(error)")
}
NSLog("TIMING saved \(features.count) observations on root context. Elapsed \(rootSaveDate.timeIntervalSinceNow) seconds")

}

localContext.reset();
NSLog("TIMING reset the local context for chunk \(chunks.count)")
NSLog("Saved chunk \(chunks.count)")
}

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

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

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

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

// NSLog("TIMING create the observation \(remoteId)")

if let remoteId = remoteId, let existingObservation = Observation.mr_findFirst(byAttribute: ObservationKey.remoteId.key, withValue: remoteId, in: context) {
// if the observation is archived, delete it
if state == .Archive {
Expand All @@ -574,7 +605,7 @@ enum State: Int, CustomStringConvertible {
}
}

existingObservation.populate(json: feature);
existingObservation.populate(json: feature, eventForms: eventForms);
if let userId = existingObservation.userId {
if let user = User.mr_findFirst(byAttribute: ObservationKey.remoteId.key, withValue: userId, in: context) {
existingObservation.user = user
Expand Down Expand Up @@ -662,7 +693,7 @@ enum State: Int, CustomStringConvertible {
if state != .Archive {
// if the observation doesn't exist, insert it
if let observation = Observation.mr_createEntity(in: context) {
observation.populate(json: feature);
observation.populate(json: feature, eventForms: eventForms);
if let userId = observation.userId {
if let user = User.mr_findFirst(byAttribute: UserKey.remoteId.key, withValue: userId, in: context) {
observation.user = user
Expand Down Expand Up @@ -752,15 +783,15 @@ enum State: Int, CustomStringConvertible {
}

@discardableResult
@objc public func populate(json: [AnyHashable : Any]) -> Observation {
@objc public func populate(json: [AnyHashable : Any], eventForms: [NSNumber: [[String: AnyHashable]]]? = nil) -> Observation {
self.eventId = json[ObservationKey.eventId.key] as? NSNumber
self.remoteId = Observation.idFromJson(json: json);
self.userId = json[ObservationKey.userId.key] as? String
self.deviceId = json[ObservationKey.deviceId.key] as? String
self.dirty = false

if let properties = json[ObservationKey.properties.key] as? [String : Any] {
self.properties = self.generateProperties(propertyJson: properties);
self.properties = self.generateProperties(propertyJson: properties, eventForms: eventForms);
}

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

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

if self.event == nil {
Expand All @@ -798,19 +829,29 @@ enum State: Int, CustomStringConvertible {
if let formsProperties = value as? [[String : Any]] {
for formProperties in formsProperties {
var parsedFormProperties:[String:Any] = formProperties;
if let formId = formProperties[EventKey.formId.key] as? NSNumber, let managedObjectContext = managedObjectContext, let form : Form = Form.mr_findFirst(byAttribute: "formId", withValue: formId, in: managedObjectContext) {
for (formKey, value) in formProperties {
if let field = form.getFieldByName(name: formKey) {
if let type = field[FieldKey.type.key] as? String, type == FieldType.geometry.key {
if let value = value as? [String: Any] {
let geometry = GeometryDeserializer.parseGeometry(json: value)
parsedFormProperties[formKey] = geometry;

if let formId = formProperties[EventKey.formId.key] as? NSNumber {
var formFields: [[String: AnyHashable]]? = nil
if let eventForms = eventForms {
formFields = eventForms[formId]
} else if let managedObjectContext = managedObjectContext, let fetchedForm : Form = Form.mr_findFirst(byAttribute: "formId", withValue: formId, in: managedObjectContext) {
formFields = fetchedForm.json?.json?[FormKey.fields.key] as? [[String: AnyHashable]]
}

if let formFields = formFields {
for (formKey, value) in formProperties {
if let field = Form.getFieldByNameFromJSONFields(json: formFields, name: formKey) {
if let type = field[FieldKey.type.key] as? String, type == FieldType.geometry.key {
if let value = value as? [String: Any] {
let geometry = GeometryDeserializer.parseGeometry(json: value)
parsedFormProperties[formKey] = geometry;
}
}
}
}
}
forms.append(parsedFormProperties);
}
forms.append(parsedFormProperties);
}
}
parsedProperties[ObservationKey.forms.key] = forms;
Expand Down
Loading

0 comments on commit 8ef3b28

Please sign in to comment.