Can't fetch objects with Pointers

I have a very simple test model:

struct Library: ParseObject {
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?

    var name: String = ""
}
struct Recipe: ParseObject {
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?

    var title: String = ""
    var library: Library?

    init(title: String) {
        self.title = title
    }

    init(objectId: String?) {
        self.objectId = objectId
    }
}

Now if I comment out Recipe.library, ParseSwift will decode the server response alright. But with it, it won’t work. I can’t see the difference between the GameScore/Level objects in the tests and my Recipe/Library objects. Help?

Here’s the server response:

{
  "results": [
    {
      "objectId": "xG4l32l9jY",
      "title": "Gâteau au fromage",
      "library": {
        "__type": "Pointer",
        "className": "Library",
        "objectId": "m8WNpqBgeD"
      },
      "createdAt": "2021-03-19T18:29:15.917Z",
      "updatedAt": "2021-03-19T18:29:15.917Z"
    }
  ]
}

Worth mentioning: saving a Recipe works fine.

In your Library struct, name should be optional, and in Recipe, title should be optional. When they are not optionals you are saying, “these keys are required for decoding”. A “parse pointer” will never contain those keys:


"library": {
        "__type": "Pointer",
        "className": "Library",
        "objectId": "m8WNpqBgeD"
      },

Of course, your original query will work (without using optionals) if you add .includAll or .include(“library”) to the end of it as the the full contents library will be fetched instead of a pointer to it.

It’s recommended to make all your keys optionals if you expect to have those objects pointed to at some point in the future. You can ensure they “act” as required through your initializers.

Wow, so simple! It works now!

You know, those decoding errors are my biggest pet peeve with the framework. They’re obscure and don’t quite point in the right direction. I don’t know if there’s anything that can be done to make them more explicit/verbose.

Thanks again!

1 Like

The errors thrown to you as a developer come directly from Swift JSON’s decoder (along with anything from the server). If you are using version 1.2.0+, you should be able to see the decoding error tacked onto the end of the ParseError, along with the original data it tried to decode.

Can you post the error you received?

I’ll note here that setting the objectId here won’t save this value on your server as objectId is skipped key when saving ParseObjects. I think the server may support setting custom keys from the client depending on the settings, but I never looked into it and currently ParseSwift doesn’t support it. So any changes to objectId are local and temporary (unless you store locally).

Indeed that has helped making the errors a little easier to debug.

That initializer is copied directly from the Playgrounds :grin: I’m only using it to create references to existing objects that I’ve created in the Dashboard. I’m taking note of the behavior you are describing though to avoid future issues!

Support for custom objectIds are available in Parse-Swift version 1.2.3+. If interested, check the api docs for enabling on the client-side. The same option will also need to be enabled server-side.

1 Like

I can’t find much documentation on how to enable this on the server. Anyway, I am not sure I would need them: I am relying on the integrity of the CoreData model and their relations until the user signs up or syncs.

I’m not sure where the docs are, but it’s a simple config setting. In the parse config, just set allowCustomObjectId = true or use the environment variable PARSE_SERVER_ALLOW_CUSTOM_OBJECT_ID .

In the case of ParseSwift, when you set allowCustomObjectId = true, it will throw an error if you don’t set an objectId when saving an ParseObject to the server.