Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to check for null in JSON with is NSNull. #8

Closed
wants to merge 4 commits into from
Closed

Add ability to check for null in JSON with is NSNull. #8

wants to merge 4 commits into from

Conversation

kreeger
Copy link
Contributor

@kreeger kreeger commented Oct 9, 2015

The inability for us to check if a key exists, but is null, in the JSON was kind of a bummer, so I wrote this up.

Note that this is different for checking if a key doesn't exist, which is where you'd use json["not_a_key"].isNil. Instead, if you have an object in the JSON as such…

{
    "can_be_null": null
}

Then you check if that object is null using the change in this PR by asking

json["can_be_null"].isNull // returns true
json["can_be_null"].isNil // returns false, because the key is there, but is not nil; it's null

This PR comes complete with unit test addition!

@jlandon
Copy link
Member

jlandon commented Oct 12, 2015

@kreeger in the event that a key is not found, isNil returns true, but isNull returns false. Maybe isNull could also check if object is nil, so that isNull is more clear in the case of an empty key.

public var isNull: Bool {
   return (object == nil) || object is NSNull
}

@kreeger
Copy link
Contributor Author

kreeger commented Oct 12, 2015

Well, the way I'm using this, I need to check that the key is there, and also if its value is null, in order to null out an associated object in my data store (it's like a server <> client sync). In this case, nil and null are two different situations. One is "nothing found," and the other is "something was found, but it's empty."

if json["feature"].isNull {
    // Nil out the feature object if this document was not assigned one.
    feature = nil
} else {
    feature = SomeObject(fromJSON: json["feature"])
}

With your change, this would force me to check if the object from the JSON is non-nil first, and then check for isNull.

if !json["feature"].isNil && json["feature"].isNull {
    // Nil out the feature object if this document was not assigned one.
    feature = nil
} else {
    feature = SomeObject(fromJSON: json["feature"])
}

And that feels odd to me.

@jlandon
Copy link
Member

jlandon commented Oct 12, 2015

In the case where json["feature"] is empty (null), is it necessary to use the initializer on it (i.e. SomeObject(fromJSON: NSNull()))? It seems like in either case, whether the key is not found or is null, feature should be nil. Is that not the case?

@kreeger
Copy link
Contributor Author

kreeger commented Oct 12, 2015

@jlandon That's not the case; SomeObject here isn't a ModelRocket.Model, it's actually a Realm Object subclass, so I'm constructing it from the JSON a little more manually.

But in this case, I do care if the key for feature is not found; at some endpoints, our JSON from our API won't return the feature node at all, in certain slimmed-down payloads, even if this object may have a feature. So if the node doesn't come down from the API, we don't nil out the feature (which, in my case, would delete any associated feature from my local data store, which is not what I want to happen). We basically want that to be a no-op on the associated feature object.

But if the feature does come down as a node from the API, and is null, that's the explicit absence of a feature from this object, and that's when I want to nil out the feature from my object.

@jlandon
Copy link
Member

jlandon commented Oct 12, 2015

Hmm, that seems like a pretty unique situation. Since ModelRocket doesn't natively support Realm, I'd say that it makes more sense for this to be added via an extension to your project. To me, isNull returning false when the key is nil could be misunderstood.

Here's what I propose:
isNil continues to check if the object is nil (i.e. the key was not found)
isNull checks if the object is nil and null (i.e. the key was not found or the value is null)

Then you could simply add an extension to your project like this:

extension JSON {
    var validKeyNullValue: Bool {
        return !isNil && isNull
    }
}

Does that seem reasonable?

@kreeger
Copy link
Contributor Author

kreeger commented Oct 12, 2015

@jlandon I still think in my mind that == nil and is NSNull are still two distinct states. However I can still make the change that you mention, and then add an extension to the JSON struct in my project and be done with it.

@kreeger
Copy link
Contributor Author

kreeger commented Oct 12, 2015

Per out-of-band discussion, I'm going to amend this PR so that we expose two computed boolean properties: hasKey for when the key is not present (and thus the inner object reference is nil), and hasValue for when the value is not present (or NSNull).

@kreeger
Copy link
Contributor Author

kreeger commented Oct 12, 2015

Tell you what — let me close this PR and open up a new one with cleaner history (#9).

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

Successfully merging this pull request may close these issues.

None yet

2 participants