Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

cezarywojcik
Copy link
Contributor

Added implementation of isValidJSONObject.

Testing is currently difficult since NSArray, NSString, and NSDictionary are not yet fully implemented, so I tested this by writing tests using the existing Foundation classes in another project. I added these tests here and commented them out since they cannot yet be used and added a TODO: to enable the tests once ready.

Let me know what you think!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would would probably be better implemented using guard to guarantee the early exit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, scratch that, I would just write inside the outer if let:

let invalid = number.doubleValue.isInfinite || number.doubleValue.isNaN || ...
return !invalid

@cezarywojcik
Copy link
Contributor Author

Addressed review comments.

Quick question about Array/Dictionary/String vs NSArray/NSDictionary/NSString though - aren't they interoperable? When I was testing this against the existing Foundation classes, it was working as intended. For example:

let arr = NSArray(array: [1])
arr is [AnyObject] // true
let dict = NSDictionary(dictionary: ["string" : 1])
dict is [String : AnyObject] // true

@phausler
Copy link
Contributor

phausler commented Dec 9, 2015

code like this:

let arr = NSArray(array: [1])
arr is [AnyObject] // true

are implicit type conversions from the objc bridging code in the swift standard library and the compiler which do not exist on all platforms: see https://github.com/apple/swift-corelibs-foundation/blob/master/Docs/Issues.md

@cezarywojcik
Copy link
Contributor Author

Gotcha, thanks for the clarification.

@cezarywojcik
Copy link
Contributor Author

This means that I can't use the filter function as well, correct? I'll update that.

@phausler
Copy link
Contributor

phausler commented Dec 9, 2015

you can if you use _swiftObject or .bridge(); but remember any bridges except the conversion between CF and NS types cost at least a function call overhead, sometimes they require a O(n) or worse traversal

@cezarywojcik
Copy link
Contributor Author

Makes more sense to avoid bridging if possible then. Updated to account for this.

@parkera
Copy link
Contributor

parkera commented Dec 9, 2015

This one is tricky, but I think we need to change this API to take [String:Any]. A user of this API in Swift should be able to pass in Swift.String objects, and without the implicit conversion from Swift.String to Foundation.NSString, it would be difficult to use the method.

@cezarywojcik
Copy link
Contributor Author

I'm a bit confused on what you mean. If we pass in an AnyObject, then we can only have an NSDictionary passed in, which, in turn means that the keys are also all AnyObjects, so the keys couldn't be a Swift.String without implicit conversion, as you said.

Are you saying that the function signature should take in an Any instead of an AnyObject and test for both Foundation.NSString, Foundation.NSArray, ... types as well as Swift.String, Swift.Array...?

@parkera
Copy link
Contributor

parkera commented Dec 10, 2015

The assumption we've decided to make here is that, in the absence of implicit bridging, we have to assume that clients are using the Swift collection and String types instead of the Foundation ones. Hopefully, once we get our bridging story fully figured out here, we can accept either String or NSString.

@cezarywojcik
Copy link
Contributor Author

Updated to check for String, Array<Any>, and Dictionary<String, Any> in place of NSString, NSArray, and NSDictionary.

Changed function signature of isValidJSONObject to take Any as input instead of AnyObject to allow for this.

Uncommented and reformatted tests.

Added TODO: to revisit the method once bridging gets fully figured out.

Let me know if this is in line with what you were thinking.


As a side note, what do you think about also accepting nil along with NSNull()?

@phausler
Copy link
Contributor

func foo(t: AnyObject) { }
foo(nil)

on darwin results in error: nil is not compatible with expected argument type 'AnyObject'

So I would be inclined to claim that NSNull is more appropriate to represent nil

@cezarywojcik
Copy link
Contributor Author

Right, an optional type would probably have to be used, but since only the internal recursive method would be checking for nil/NSNull (since top-level objects can only be dictionaries or arrays), only the internal method's signature would have to change to support nil, so the actual isValidJSONObject would still only accept non-optional input.

What I mean:

public class func isValidJSONObject(obj: Any) -> Bool {
     func isValidJSONObjectInternal(obj: Any?) -> Bool {
                                            ^
...

@parkera
Copy link
Contributor

parkera commented Dec 10, 2015

The current NSJSONSerialization only uses NSNull to represent nil. I don't think that we bridge a nil optional to NSNull in Objective-C mode, so if we accept an optional type here then I suspect we lose our cross-platform compatibility...

I think it makes total sense to use optionals for this (something we obviously could not do in Objective-C). But that would be an API change, so we'd have to discuss it separately.

@cezarywojcik
Copy link
Contributor Author

That makes sense - it's definitely something that I think is worth looking into in the long run.

Is there anything else that's blocking a merge for this?

@phausler
Copy link
Contributor

Not really, just need to finish running tests and verify a good state before merging anything else in this morning (last night there were some test breaks that got merged in that I am still trying to account for)

@cezarywojcik
Copy link
Contributor Author

Sounds good. As a quick related note, currently on master, in main.swift, TestNSJSONSerialization appears twice; this PR removes one of those instances.

@parkera parkera self-assigned this Dec 10, 2015
phausler added a commit that referenced this pull request Dec 10, 2015
NSJSONSerialization isValidJSONObject Implementation
@phausler phausler merged commit 38c47ea into swiftlang:master Dec 10, 2015
@cezarywojcik
Copy link
Contributor Author

The spec for the function says that any NSNumber that is not NaN or Infinity should be accepted. I don't think that we can make assumptions about what kind of value this is. Since this needs to be cross-platform, I think that it's better to check both. Feel free to submit another PR that removes the floatValue checks if you think that it doesn't matter - can get feedback about this in a new PR.

@phausler
Copy link
Contributor

The more tests we have the better even if they are slightly redundant; if anything it ensures consistency with little cost since these tests are rather short in execution time.

atrick pushed a commit to atrick/swift-corelibs-foundation that referenced this pull request Jan 12, 2021
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.

5 participants