Skip to content
This repository has been archived by the owner on Jan 25, 2019. It is now read-only.

Serializing Resources for storage in UserDefaults #184

Open
Croge32 opened this issue May 23, 2017 · 4 comments
Open

Serializing Resources for storage in UserDefaults #184

Croge32 opened this issue May 23, 2017 · 4 comments

Comments

@Croge32
Copy link

Croge32 commented May 23, 2017

I'm trying to use the Serializer to store objects in UserDefaults so we can load resources up without always doing API requests.

I'm trying to serialize an array of objects that each contain toOne/toMany relationships.

So right now I'm doing:

func persistShoppingList() {
    let serializer = getShoppingListSerializer()
    let shoppingListData = try! serializer.serializeResources(contents, options: [.IncludeID, .IncludeToOne, .IncludeToMany])
    UserDefaults.standard.set(shoppingListData, forKey: "shoppingListArray")
}

However when I deserialize this, I have none of the attributes of the relationship objects inside of contents, only their ids. Here is how I'm deserializing:

  func checkShoppingListPersistence() {
    let serializer = getShoppingListSerializer()

    if let dataFromDefaults = UserDefaults.standard.data(forKey: "shoppingListArray") {
      let contentsJson = try! serializer.deserializeData(dataFromDefaults, mappingTargets: contents).data
      contents = (contentsJson as? [DFPContents])!

      tableView.reloadData()
      tableViewHeight.constant = tableView.contentSize.height
    } else {
      getShoppingList()
    }
  }

I'm not exactly sure what mappingTargets is for. Maybe I'm using that wrong?

How would I go about including the attributes of these relationships when serializing/deserializing?

@markst
Copy link

markst commented May 26, 2017

@Croge32 have you an example of the JSON which has been written to UserDefaults?

@Croge32
Copy link
Author

Croge32 commented May 26, 2017

@markst The structure of the object's model is as follows:

class DFPContents: Resource {
  var quantity: NSNumber?
  var sequence: NSNumber?
  var wasConsumed: NSNumber?
  var calories: NSNumber?
  var foodId: NSNumber?
  var servingId: NSNumber?

  var dfpMeal: DFPMeal?
  var food: Food?
  var portion: Portion?

  override class var resourceType: ResourceType {
    return "dfp_contents"
  }

  override class var fields: [Field] {
    return fieldsFromDictionary([
      "quantity": Attribute(),
      "sequence": Attribute(),
      "calories": Attribute(),
      "wasConsumed": BooleanAttribute().serializeAs("was_consumed"),
      "foodId": Attribute().serializeAs("food_id"),
      "servingId": Attribute().serializeAs("serving_id"),
      "dfpMeal": ToOneRelationship(DFPMeal.self).serializeAs("dfp_meal"),
      "food": ToOneRelationship(Food.self),
      "portion": ToOneRelationship(Portion.self),
    ])
  }

...

I'm trying to serialize an array of these DFPContents objects. They are not coming from JSON, which I suspect is part of the problem. Basically when I just serialize the array itself, the children do populate and their ID and types are assigned, but each of their attributes are nil. I see that in the library itself, it looks like responses are able to be parsed into a JSONAPIDocument object where included resources can be specified, which I'm unable to do on my level.

I did however find a workaround. I noticed that if I serialize the object AND it's children all in a Resource array, the parents children are also populated with the children's attributes. So I'm able to pass an items array of type [Resource] into the serializer and then deserialize and pick out just the objects I want. However this is ugly and feels hacky.

Here is how I'm serializing in order to get the child attributes to be non-nil:

func persistShoppingList() {
    let serializer = self.getShoppingListSerializer()

    var items = [Resource]()
    let contents = self.contents as [Resource]
    let foods = self.contents.flatMap {
      return $0.food!
    } as [Resource]
    let portions = self.contents.flatMap {
      return $0.portion!
    } as [Resource]

    items.append(contentsOf: contents)
    items.append(contentsOf: foods)
    items.append(contentsOf: portions)

    let data = try! serializer.serializeResources(items, options: [.IncludeToMany, .IncludeToOne, .IncludeID])
    cache["shoppingListArray"] = data as NSData
    tableView.reloadData()
    tableViewHeight.constant = tableView.contentSize.height
  }

I have also abandoned UserDefaults and am using a caching library now.

Any further insights? I know this probably sounds a bit confusing.

@Croge32
Copy link
Author

Croge32 commented Jun 2, 2017

@markst Any ideas at all? Any suggestions on how I can achieve data persistence using Spine?

@Kamajabu
Copy link

Kamajabu commented Aug 10, 2017

It's most probably not a reason, but have you remembered about adding:

 serializer.registerResource(Food.self)
 serializer.registerResource(Portion.self)

Etc.?

EDIT: Nope, it doesn't help :(

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants