0

I have an NSManagedObject class that stores, among other things, a JSON string that comes from a WkWebView form. The form in the web view allows the user to add images to the form; when the form is submitted, it is passed to the Cocoa layer via userContentController:didReceiveScriptMessage as a JSON string. The images are included as Base64 encoded data URLs.

This works, but users add more images and larger images than anticipated, and it is rather uncool to store BLOBs in a database, IMHO. So I want to save the images into files in the app doc dir and patch the JSON string to refer to the images via file URL.

The sandbox directory (and thus the documents directory) changes on every app launch, so I cannot store absolute URLs in the database. Instead, I use a placeholder, [APP_DOC_DIR].

So basically the JSON data images have 3 states:

  • Base64 data URLs as created by JS code in WkWebView
  • File URLs with [APP_DOC_DIR] placeholder
  • File URLs with correct absolute path when displaying the data in WkWebView

To make the changes at the appropriate locations and moments, I override the form data setter and getter of my NSManagedObject instance.

#define FORM_DATA_KEY @"formData"

/// Form data setter
- (void) setFormData:(NSString *)form_data
{
  // abbreviated heavily, just showing the concept
  NSMutableString *data = form_data;
  for (;;) {
    // Find base64 data URL
    // Save resulting NSData in a file
    // Replace data URL with URL to the file, using [APP_DOC_DIR] placeholder
  }
  
  // Update the value Core Data sees
  [self willChangeValueForKey:FORM_DATA_KEY];
  [self setPrimitiveValue:data forKey:FORM_DATA_KEY];
  [self didChangeValueForKey:FORM_DATA_KEY];

}

/// Form data getter
- (NSString*) formData
{
  NSMutableString *data = [self primitiveValueForKey:FORM_DATA_KEY];
  NSString *docsUrl = [NSURL fileURLWithPath:thisApp.docDir].absoluteString;

  for (;;) {
    // Replace all occurrences of [APP_DOC_DIR] with docsUrl
  }

  return data;
}

Basically, that's it. The replacement code is fast and works.

But the form data stored in the database contains absolute URLs. Apparently, not the value set in the setter with setPrimitiveValue is being stored in the DB but the value returned from the getter.

What am I doing wrong?

1 Answer 1

0

Answering my own question...

I have not found why it failed overriding getter and setter. What finally solved it for me was to create dedicated getters and setters and leave the Core Data generated property with its getter and setter alone. I don't use it anymore at all, nowhere.

- (void) setFormDataWithBlobs:(NSString*) data
{
  // Store BLOBs as files
  // Replace BLOB base64 strings with file URLs using [APP_DOC_DIR] placeholder

  // Then save the whole thing in Core Data:
  [self willChangeValueForKey:FORM_DATA_KEY];
  [self setPrimitiveValue:data forKey:FORM_DATA_KEY];
  [self didChangeValueForKey:FORM_DATA_KEY];
}

- (NSString*) getPatchedFormData
{
  // Get form data with placeholders from Core Data
  NSString *s = [self primitiveValueForKey:FORM_DATA_KEY];
  NSMutableString *data = [s mutableCopy];

  // Replace [APP_DOC_DIR] with actual application docs dir
  // ...

  return data;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.