0
votes

While working to add cross-platform support to a NativeScript plugin, there are areas of the plugin that will need to preserve an Object state. This means that at a given time, the state of the data needs to be preserved and stored within NativeScript (TypesScript/JavaScript) and reinstated without data corruption.

While this seems to be a feat pretty straightforward in many JAVA libraries used for the Android side of the plugin, I am unsure how to replicate this for iOS development.

1
What type of data are you wanting to Preserve? I frequently preserve the state of the application in either localstorage or sqlite... No need for anything more complex. - Nathanael
So in my use-case I am looking to preserve information that I believe are data buffers/streams. The specific class can be found here that I've been playing with: github.com/ChatSecure/SignalProtocol-ObjC/blob/master/Classes/… What I need to be able to do is serialize this class instance, store it locally (like through sqlite), and then restore it as necessary. This is why I needed to serialize it into a base64 string. - Pixxl
Looking at that class you can init it with having to serialize the class; all you need to have stored in your sqlite is the pub/private key and then re-instantiate the class from that data. Seems a whole lot simpler than trying to serialize the whole class. - Nathanael
So that is just it, I am trying to serialize in this example the pub/private key specifically. Unfortunately I do not have the skillset to understand how to do that at this point in time with Objective-C so serializing the class works currently. The pub/private keys appear to be buffer objects and if there was a way I could turn encode those as base64 strings and decode them later then I could accomplish the same feat. - Pixxl
Both pub and priv keys a NSData objects. So you can serialize them almost the exact same way as you did below. :D - Nathanael

1 Answers

1
votes

Researching this topic online can lead to various answers, most of which seem to require the developer to create specific methods on a given Object/Class in order to support serialization.

Option 1 - NSCoding Protocol

The NSCoding protocol — Source (Apple) — declares the two methods that a class must implement so that instances of that class can be encoded and decoded. This capability provides the basis for archiving (where objects and other structures are stored on disk) and distribution (where objects are copied to different address spaces).

The two methods mentioned are:

- (void) encodeWithCoder:(NSCoder*)encoder;
- (id) initWithCoder:(NSCoder*)decoder;

While this could work in most circumstances, this would require the NativeScript developer to figure out a way to create yet another wrapper for an iOS library (likely to be a pod package). This is more hands on than needs to be and may not be available in most situations.

Option 2 - NSKeyedArchiver/NSKeyedUnarchiver

The NSKeyedArchiver and companion NSKeyedUnarchiver protocols provide a way to encode/decode objects (and scalar values) into an architecture-independent suitable for storage in a file.

This option seems less intrusive and allows for the archived object to be turned into something sharable between environments such as base64:

declare var NSDataBase64EncodingEndLineWithLineFeed;
declare var NSDataBase64DecodingIgnoreUnknownCharacters;

// archive class instance as base64 string
const archivedObject = NSKeyedArchiver.archivedDataWithRootObject(someClassInstance);
const base64Archive = archivedObject.base64EncodedStringWithOptions(NSDataBase64EncodingEndLineWithLineFeed);

// unarchive back into a class instance
const rawData = NSData.alloc().initWithBase64EncodedStringOptions(base64Archive, NSDataBase64DecodingIgnoreUnknownCharacters);
const newClassInstance = NSKeyedUnarchiver.unarchivedObjectOfClassFromDataError(NSObject, rawData);

I was able to learn both of these concepts from an old article lost in time (but thankfully saved due to the WayBackMachine) — CocoaHeads - NSCoding

In addition to the information above, I believe one could also use NativeScript to extend an existing ObjC Class and add the required encodeWithCoder and initWithCoder methods. While I have not needed to do this or try this out, if myself or someone else happens to experiment with this with a good result please let me know and I'll add that example here.

For more information about creating a subclass by extending Objective-C classes in NativeScript, please check out this source: https://docs.nativescript.org/core-concepts/ios-runtime/how-to/ObjC-Subclassing

For more information about Objective-C classes in NativeScript, please read up here: https://docs.nativescript.org/core-concepts/ios-runtime/types/ObjC-Classes