Storage

This page explains how iink SDK lets you store content and load it again later.

Structure of the model

Interactive Ink SDK stores content using the following structures:

  • IINKContentPackage - A Package is a container storing ink and its interpretation as an ordered collection of parts. It can be saved as a file on the file system and later reloaded or exchanged between users.
  • IINKContentPart - A part corresponds to a standalone content unit that can be processed by iink SDK. Each part has a specific type (“Text”, “Math”, “Drawing, ““Diagram” or “Text Document”) that can be retrieved via its type property.
The complete list of supported part types can be found here.

It is possible to get the number of parts of a given package via its partCount property and access an individual part by calling getPart:error: and pass it the 0-based index of the part to load.

Although a content part sometimes hosts a single content block, both concepts are not equivalent. A part corresponds to a serialization unit, while a block corresponds to a semantic unit that can be manipulated.

Serialization

Interactive Ink SDK uses the file system to limit the amount of RAM that is required at a given point in time, as well as to store temporary files. It also provides serialization/deserialization methods to let application save/load MyScript data, either for persistence needs or to exchange it between users.

MyScript iink SDK serialization format is optimized for speed and compactness, but is not easily readable. If you want to parse the content of the interactive model, refer to the import/export section.

Creating or loading content

To create a new content package, call the createPackage:error: method of the IINKEngine object. Alternatively, you can load an existing package from the file system by calling openPackage:error:.

Both methods take in parameter the name of the file corresponding to the package on the file system.

#import <iink/IINK.h>

...

NSError *error = nil;

// Create a new package
IINKContentPackage *newPackage = [engine createPackage:@"newPackage.iink" error:&error];

// Load an existing package
IINKContentPackage *existingPackage = [engine openPackage:@"existingPackage.iink" error:&error];

Temporary folder

Even if you do not intend to explicitly save any content, MyScript iink SDK requires a read/write access to at least one folder on the file system: the temporary folder, where it will output the intermediate files it is working on.

By default, iink SDK uses the folder where the package file is located. It may however be relevant (and even mandatory on certain platforms) to choose another folder. This can be achieved by setting the value of content-package.temp-folder in the configuration of the engine.

If it does not exist, the folder will be created if you save the corresponding package. It may also be automatically created by iink SDK in case it has a need to reduce its memory usage or when handling some particular objects such as images.

Saving content

Interactive Ink SDK provides two distinct methods to save content: saveWithError: and saveToTempWithError:, both to be called on the IINKContentPackage instance to consider.

It is important to understand the distinction between them, as they play different roles:

  • saveWithError: will serialize all data into a zip archive named after the package, whether such data is on the memory or if it was off-loaded into the temporary folder. The resulting file is self-contained, and can be reloaded at a later point. Due to the compression, this method is rather slow.
  • saveToTempWithError: will save the content that was loaded into the memory to the temporary folder. As it only writes the content that was in the memory at a given point in time and does not require compression, calling this method is much faster. It can let iink SDK recover such data if it was forced to exit without saving to the zip archive.

The following diagram explains how iink SDK manages the memory, as well as the role of the different save operations:

ContentPackage “content.iink” (in RAM) content.iink (zip archive) Temporary folder content.iink-files fragment 1 fragment 2 fragment 3 first “save” create archive and commit content “open” partial extraction “saveToTemp” off-load memory <automatic> partial extraction <automatic> partial load or off-load “save” commit changes
By default, data corresponding to a content package is stored in a folder named after this package by appending the -files suffix and located in the same folder.

Metadata

You can attach metadata to both IINKContentPart and IINKContentPackage objects, and they will be serialized with the file. This can prove useful to store client-specific parameters.

Use the metadata property to store and retrieve the metadata attached to the object.

// Retrieve the metadata from a part
IINKParameterSet *metadata = part.metadata;

// Set and Get (key, value) pairs
...

// Store the metadata back into the part
part.metadata = metadata;

The structure representing metadata is an IINKParameterSet and is manipulated the exact same way as engine configuration parameters.

Back to the example

The calculator requires setting a package that iink SDK can use to store the content it is working on.

In addition, the user needs to be able to restore the state of the last session if he exits and relaunches the app. This can also prove useful on systems such as Android, where the content should be saved then restored when rotating the screen.

@property (nonatomic, strong) IINKContentPart *part;
@property (nonatomic, strong) IINKContentPackage *package;

NSString *const packageName = @"calculator.iink";

- (void)saveContent
{
  // Save history in part metadata
  [self saveHistory];
  // Save the content package to the file system
  [self.package saveWithError:nil];
}

- (void)openContent
{

  if ([[NSFileManager defaultManager] fileExistsAtPath:packageName])
  {
    self.package = [self.engine openPackage:packageName error:nil];
    self.part = [self.package getPartAt:0 error:nil];
    // Load history from part metadata
    [self loadHistory];
  }
  else
  {
    // Create a content package to provide the SDK with a place to work
    self.package = [self.engine createPackage:packageName error:nil];
    // Create a Math part
    self.part = [self.package createPart:@"Math" error:nil];
    // Create history
    self.history = [NSMutableArray array];
  }
}

You can make sure to call openContent: after launching the app to always have a package to work on.

You can also use metadata to store the history (an array of LaTeX strings):

@property (nonatomic, strong) NSMutableArray<NSString *> *history;

- (void)loadHistory
{
  NSArray<NSString *> *history = [self.part.metadata getStringArray:@"history" error:nil];
  self.history = [NSMutableArray arrayWithArray:history];
}

- (void)saveHistory
{
  IINKParameterSet *parameterSet = self.part.metadata;
  [parameterSet setStringArray:@"history" value:self.history error:nil];
  editor.part.metadata = parameterSet;
}

How to actually fill the history will be left for the import/export page of this guide.

Let’s now see how iink SDK can render some content.

We use cookies to ensure that we give you the best experience on our website Read the privacy policy