Cortex Objects

This is a tutorial on how to handle Cortex objects in the Cortex iOS SDK v1.8.6+

The Cortex iOS SDK makes it easy to work with your custom object in your iOS app. Below are examples on how to do so with the example custom prescription object, c_prescription, created in the Data Model Setup guide.

1. Creating the custom class

First, we need to create a custom class for our new custom prescription object as a subclass of MDObjectInstance. MDObjectInstance is the base class to model any custom object instance in Cortex.

The header file Prescription.h would look something like the following. If you are writing in Swift, there won't be a header file.

@interface Prescription : MDObjectInstance

@property (nonatomic, strong) NSDate *date;
@property (nonatomic, strong) NSNumber *dispense;
@property (nonatomic, strong) MDReference *patient;
@property (nonatomic, strong) MDReference *provider;
@property (nonatomic, strong) NSNumber *refills;
@property (nonatomic, strong) NSString *details;

@end
// No header files in Swift :)

And the implementation file Prescription.m --or Prescription.swift, would look something like the following:

@implementation Prescription

- (NSDate *)date
{
    return [self dateValueWithPropertyName:@"c_date"];
}

- (NSNumber *)dispense
{
    return [self numberValueWithPropertyName:@"c_dispense"];
}

- (MDReference *)patient
{
    return [self referenceValueWithPropertyName:@"c_patient"];
}

- (MDReference *)provider
{
    return [self referenceValueWithPropertyName:@"c_provider"];
}

- (NSNumber *)refills
{
    return [self numberValueWithPropertyName:@"c_refills"];
}

- (NSString *)details
{
    return [self stringValueWithPropertyName:@"c_rx"];
}

@end
import Foundation

class Prescription : MDObjectInstance {
    var date: Date? {
        get {
            return self.dateValue(withPropertyName:"c_date")
        }
    }
    
    var dispense: NSNumber? {
        get {
            return self.numberValue(withPropertyName:"c_dispense")
        }
    }
    
    var patient: MDReference? {
        get {
            return self.referenceValue(withPropertyName:"c_patient")
        }
    }
    
    var provider: MDReference? {
        get {
            return self.referenceValue(withPropertyName:"c_provider")
        }
    }
    
    var refills: NSNumber? {
        get {
            return self.numberValue(withPropertyName:"c_refills")
        }
    }
    
    var details: String? {
        get {
            return self.stringValue(withPropertyName:"c_rx")
        }
    }
}

2. Registering the new object

Now that we have a new custom class Prescription we want to use for the c_prescription object instances, let's register it by doing the following:

#import "Prescription.h"

...
  
[MDAPIClient registerContext:@"c_prescription" pluralContext:@"c_prescriptions" type:nil withClass:[Prescription class]];
MDAPIClient.registerContext("c_prescription", pluralContext: "c_prescriptions", type: nil, with: Prescription.self)

Now, whenever you query routes that return c_prescription instances, Cortex iOS will return instances of your custom class Prescription:

[[Medable client]
 listObjectsWithContext:@"c_prescriptions"
 parameters:nil
 callback:^(NSArray<MDObjectInstance *> * _Nullable objects, NSNumber * _Nullable hasMore, MDFault * _Nullable fault)
 {
     // "objects" will contain instances of Prescription instead of MDObjectInstance(s) :)
 }];
Medable.client().listObjects(withContext: "c_prescriptions", parameters: nil) {
            (objects: [MDObjectInstance]?, hasMore: NSNumber?, fault: MDFault?) in
            // "objects" will contain instances of Prescription instead of MDObjectInstance(s) :)
        }

This also works for expanded references to related objects you have registered.

For example, if in another custom object you have a reference property named c_prescription that relates to the c_prescription object and you query that custom object with expand=c_prescription, then the MDReference @ expandedObjectReference will also be an instance of Prescription automagically.

MDAPIParameters *expandPrescription = [MDAPIParameterFactory parametersWithExpandPaths:@[ @"c_prescription" ] prefixPath:nil];

MDObjectId *identifier = ...;

[[Medable client]
 objectWithContext:@"c_someOtherCustomObjectWithAReferenceToAPrescription"
 objectId:identifier
 parameters:expandPrescription
 callback:^(MDObjectInstance * _Nullable object, MDFault * _Nullable fault)
 {
     MDReference *referenceToPrescription = [object referenceValueForPropertyWithName:@"c_prescription"];
     Prescription *myPrescriptionInstance = (Prescription *)referenceToPrescription.expandedObjectReference;
 }];
let identifier: MDObjectId = MDObjectId.init(string: "your prescription _id")!
let expandPrescription = MDAPIParameterFactory.parameters(withExpandPaths: [ "c_prescription" ], prefixPath: nil)

Medable.client().object(withContext: "c_someOtherCustomObjectWithAReferenceToAPrescription",
                        objectId: identifier,
                        parameters: expandPrescription)
{
    (object: MDObjectInstance?, fault: MDFault?) in
    
    if let object = object {
        let referenceToPrescription = object.referenceValue(withPropertyName: "c_prescription")
        let myPrescriptionInstance: Prescription = referenceToPrescription?.expandedObjectReference as! Prescription
    }
    
}

3. Using custom objects with different types

In Cortex, you can create a custom context and subclass it by using types. In this case the object name will be the same for both custom classes, however they will differ in type.

Let's suppose you have two types of prescriptions, both share all the same base properties but each one has additional properties only usable on each type of prescription.

For the simplicity's sake, let's suppose that we have two types of prescriptions, "A" and "B". PrescriptionA has all the properties from Prescription plus prescriptionAProperty, and PrescriptionB has all the properties from Prescription plus prescriptionBProperty...

You'd accomplish this in your app in the following manner:

  1. Create a PrescriptionA class that is a subclass of Prescription and add the prescriptionAProperty to the class.
// PrescriptionA.h
#import "Prescription.h"

@interface PrescriptionA : Prescription
@property (nonatomic, strong) NSString *prescriptionAProperty;
@end
// No header files in Swift :)
// PrescriptionA.m
#import "PrescriptionA.h"

@implementation PrescriptionA

- (NSString *)prescriptionAProperty
{
    return [self stringValueWithPropertyName:@"c_prescriptionAProperty"];
}

@end
class PrescriptionA : Prescription {
    var prescriptionAProperty: String? {
        get {
            return self.stringValue(withPropertyName: "c_prescriptionAProperty")
        }
    }
}
  1. Create a PrescriptionB class that is a subclass of Prescription and add the prescriptionBProperty to the class.
// PrescriptionB.h
#import "Prescription.h"

@interface PrescriptionB : Prescription
@property (nonatomic, strong) NSString *prescriptionBProperty;
@end
// No header files in Swift :)
// PrescriptionB.m
#import "PrescriptionB.h"

@implementation PrescriptionB

- (NSString *)prescriptionBProperty
{
    return [self stringValueWithPropertyName:@"c_prescriptionBProperty"];
}

@end
class PrescriptionB : Prescription {
    var prescriptionBProperty: String? {
        get {
            return self.stringValue(withPropertyName: "c_prescriptionBProperty")
        }
    }
}
  1. Then register both classes using the same context c_prescription while specifying the appropriate type.
#import "PrescriptionA.h"
#import "PrescriptionB.h"

...
  
[MDAPIClient registerContext:@"c_prescription" pluralContext:@"c_prescriptions" type:@"c_A" withClass:[PrescriptionA class]];
[MDAPIClient registerContext:@"c_prescription" pluralContext:@"c_prescriptions" type:@"c_B" withClass:[PrescriptionB class]];
MDAPIClient.registerContext("c_prescription", pluralContext: "c_prescriptions", type: "c_A", with: PrescriptionA.self)
MDAPIClient.registerContext("c_prescription", pluralContext: "c_prescriptions", type: "c_B", with: PrescriptionB.self)