GithubHelp home page GithubHelp logo

json-swift's People

Contributors

aspyrx avatar atestu avatar bygri avatar drhaynes avatar ingmarstein avatar jjjayway avatar natashatherobot avatar owensd avatar rosskimes avatar sirwart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

json-swift's Issues

dyld_fatal_error: XCode 6.1 compiled code crashes on iPhone but not Simulator.

I have a really weird bug.

JSON cannot be parsed by my iPhone 6 that runs iOS 8.1. It parses fine with the iPhone 6 Simulator.

This is an example of the code that I am trying to execute:

func testParsingObject() {      
        let str = NSString(string: "{}")
        let data = str.dataUsingEncoding(NSUTF8StringEncoding)

        let json = JSON.parse(data!) // This line fails.
}

func testParsingNumber() {      
        let str = NSString(string: "{\"number\": 50}")
        let data = str.dataUsingEncoding(NSUTF8StringEncoding)

        let json = JSON.parse(data!) // This line fails.
}

func testParsingString() {      
        let str = NSString(string: "{\"string\":\"here is a string\"}")
        let data = str.dataUsingEncoding(NSUTF8StringEncoding)

        let json = JSON.parse(data!) // This line fails.
}

Here is the kind of error crash that I am seeing (I just checked and it happens irrelevant of the data I pass in):

#0  0x0000000120009088 in dyld_fatal_error ()
#1  0x000000012000be48 in dyld::halt(char const*) ()
#2  0x000000012000bf18 in dyld::fastBindLazySymbol(ImageLoader**, unsigned long) ()
#3  0x0000000197ba5198 in dyld_stub_binder ()
#4  0x00000001007789c8 in JSONLib.JSValue.parseObject (JSONLib.JSValue.Type)<A : Swift.SequenceType>(JSONLib.ReplayableGenerator<A>) -> (value : Swift.Optional<JSONLib.JSValue>, error : Swift.Optional<JSONLib.Error>) ()
#5  0x0000000100777bfc in JSONLib.JSValue.parse (JSONLib.JSValue.Type)<A : Swift.SequenceType>(JSONLib.ReplayableGenerator<A>) -> (value : Swift.Optional<JSONLib.JSValue>, error : Swift.Optional<JSONLib.Error>) ()
#6  0x0000000100776578 in JSONLib.JSValue.parse (JSONLib.JSValue.Type)(Swift.UnsafeBufferPointer<Swift.UInt8>) -> (value : Swift.Optional<JSONLib.JSValue>, error : Swift.Optional<JSONLib.Error>) ()
#7  0x0000000100777a68 in JSONLib.JSValue.parse (JSONLib.JSValue.Type)(ObjectiveC.NSData) -> (value : Swift.Optional<JSONLib.JSValue>, error : Swift.Optional<JSONLib.Error>) ()
#8  0x000000010012ead8 in Spokes.AppDelegate.testParsingObject (Spokes.AppDelegate)() -> () at /Users/sebinsua/Development/Spokes/Spokes/AppDelegate.swift:40

I have hardcoded the data and am executing it from the AppDelegate to prove to myself that it's not related to any other logic I have in play and seems to be dependent on whether we've compiled for a device or not.

Any ideas? I'll come back if I work anything out myself.

Pretty printing arrays yields invalid json

pretty printing a .JSArray is missing the opening brace like:

"something": 
{
   "a": "a",
   "b": "b",
   "c": "c"
}
]

when this is expected

"something": 
[
{
   "a": "a",
   "b": "b",
   "c": "c"
}
]

A possible fix is to replace line 251 of JSValue with:
case .JSArray(let array): return "[\(newline)" + (array.map({ "\(nextIndent)\($0.prettyPrint(indent, level + 1))" })) .joinWithSeparator(",\(newline)") + "\(newline)\(currentIndent)]"

Control characters are not unescaped

Currently, json-swift only handles escaped quote characters, but according to ECMA-404 (json.org), there are other control sequences which need to be unescaped while parsing strings, i.e. ", , /, \b, \f, \n, \r, \t and \u.

The following test fails with the current HEAD:

func testParseStringWithEscapedControlCharacters() {
    let string = "\"\\\\\\/\\n\\r\\t\""
    let jsvalue = JSValue.parse(string)

    XCTAssertTrue(jsvalue.error == nil, jsvalue.error?.userInfo?.description ?? "No error info")
    XCTAssertEqual(jsvalue.value!.string!, "\\/\n\r\t")
}

Erroneously parsed strings

json-swift will parse these strings, even though they are not JSON:

[-]
[0.3e+]
[0.3e]
[0E+]
[0E]
[0e+]
[0e]
[1.0e+]
[1.0e-]
[1.0e]

Does not compile with 6.3 beta 4

diff --git a/src/JSValue.Parsing.swift b/src/JSValue.Parsing.swift
index e9cdd8e..26dac32 100644
--- a/src/JSValue.Parsing.swift
+++ b/src/JSValue.Parsing.swift
@@ -268,7 +268,7 @@ extension JSValue {
                 fallthrough

             case (_, Token.Zero...Token.Nine, NumberParsingState.ExponentDigits):
-                exponent = exponent * 10 + codeunit - Token.Zero
+                exponent = exponent * 10 + Int(codeunit) - Int(Token.Zero)

             case (_, Token.Period, NumberParsingState.Whole):
                 state = .Decimal
@@ -383,11 +383,11 @@ extension JSValue {

     private static func parseHexDigit(digit: UInt8) -> Int? {
         if Token.Zero <= digit && digit <= Token.Nine {
-            return digit - Token.Zero
+            return Int(digit - Token.Zero)
         } else if Token.a <= digit && digit <= Token.f {
-            return 10 + digit - Token.a
+            return Int(10 + digit - Token.a)
         } else if Token.A <= digit && digit <= Token.F {
-            return 10 + digit - Token.A
+            return Int(10 + digit - Token.A)
         } else {
             return nil
         }

Unpretty stringify?

In JavaScript I can do this to receive a string with no spaces:

JSON.stringify(json, null, 0);

I've tried this but it didn't work as I expected:

json.stringify(indent: "")

Unicode decoding issue

It seems that this library isn't parsing the unicode value \u0026 within a string correctly.

The string I'm getting (in this case from the Instagram API) is:

access_token=29347\u0026max_id=80776

Which should translate to:

access_token=29347&max_id=80776

Here's the output from json-swift compared to the python equivilant.

let string = "\"access_token=29347\\u0026max_id=80776\""
println(string)
"access_token=29347\u0026max_id=80776"  // string literal is valid
let jsvalue = JSValue.parse(string)
println(jsvalue)
// Prints (Optional("access_token=293476200max_id=80776"), nil)

As you can see, what should have been decoded into "&" is instead replaced with "6200"

Python:

>>> import json
>>> value = json.loads('"access_token=29347\u0026max_id=80776"')
>>> if value == "access_token=29347&max_id=80776":
...     print "Passed"
Passed

Array order different in app than in JSON API

When I look at the JSON object that this is parsing, the order is not the same as the end parsed data. I have ordered the array in the API, but when I loop through the array in the app, the order is different.

How to install?

Show I just drag 'src' into the project and add to targets?

Problem since Beta 6 - "'JSON' cannot be constructed because it has no accessible initializers"

I've updated to the newest Xcode, pulled down the latest changes, and found that trying to create a JSON object throws up a compiler error. I was doing things like so:

    var error: NSError?
    let bundlePath = NSBundle.mainBundle()
    let jsonPath = bundlePath.pathForResource(filename, ofType: "json")
    let jsonData = NSData.dataWithContentsOfFile(jsonPath!, options: .DataReadingMappedIfSafe, error: nil)
    let jsonDict = NSJSONSerialization.JSONObjectWithData(jsonData, options: .MutableContainers, error: &error) as NSDictionary
    let json = JSON(jsonDict)

IIRC it was Beta 5 that added the access control stuff, so I wasn't quite sure what had changed here. Adding public to JSValue's init doesn't work. I'm getting more comfortable with Swift (thanks for the blog posts!) and iOS development, but that was basically the limit of my ability to debug things. Any ideas what might be going on?

Strange inconsistency when unwrapping a string

I'm pulling in some data from the Instagram API and I'm getting something very strange go on when using this json library.

The following code does not fall into the if block, so nextURLString is never unwrapped, as if the value does not exist:

if let nextURLString = json["pagination"]["next_url"].string {
    self.nextPaginationURL = NSURL(string: nextURLString) // doesnt exeute
}

However a quick check in the console shows that the value does exist at that path:

(lldb) po json["pagination"]["next_url"].string!
"https://api.instagram.com/v1/users/..."

Strangely, the following code (as an alternative to the if let unwrapping) does work, and the code in the if block is executed.

let nextURLString = json["pagination"]["next_url"].string
if nextURLString != nil {
    self.nextPaginationURL = NSURL(string: nextURLString!) // this *is* executed
}

Any idea why this could be?

Alternative to BufferedGenerator

I thought the whole

buffer.next()
while buffer.current != nil {
    if let unicode = buffer.current { // ... somewhere, buffer.next() is called

dance was kind of ugly: you're dealing with the overhead of using a generator, but receiving none of the benefits it provides (e.g. for in loops). Also, using a struct for your BufferedGenerator seems odd -- you end up using a class as a backing store anyway, and having it as a struct means using inout parameters all over the place. There's a discussion on the dev forums that argues the case why GeneratorTypes should, in general, just be reference types.

Anyway, I took a different view on the parsing issue -- it's not that you need access to the "current" element so much as it is that determining what sub-parser to use forces the generator to consume one too many characters. Really, if you could just rewind the generator back a character, everything would be simple. So I wrote a class that lets you do that:

/// Creates a `GeneratorType`/`SequenceType` that allows rewinding and can be passed around.
final public class RewindableGenerator<S : CollectionType where S.Index : BidirectionalIndexType> : GeneratorType, SequenceType {
    typealias Sequence = S

    private var currentIndex: Sequence.Index
    private let prestartIndex: Sequence.Index

    private let seq: Sequence

    // store the `current` element, but it's not really necessary
    private(set) var current: Sequence.Generator.Element?

    /// Initializes a new `RewindableGenerator<S>` with an underlying `CollectionType`.
    /// Requires that `CollectionType.Index` be a `BidirectionalIndexType`.
    ///
    /// :param: sequence the sequence that will be used to traverse the content.
    public init(_ sequence: Sequence) {
        self.seq = sequence
        self.currentIndex = sequence.startIndex
        self.prestartIndex = sequence.startIndex.predecessor()
    }

    /// Moves the `current` element to the next element if one exists.
    ///
    /// :return: The `current` element or `nil` if the element does not exist.
    public func next() -> Sequence.Generator.Element? {

        if currentIndex == seq.endIndex {
            return nil
        }

        currentIndex = currentIndex.successor()

        if currentIndex != seq.endIndex {
            self.current = seq[currentIndex]
        } else {
            self.current = nil
        }
        return self.current
    }

    /// Moves the `current` element to the previous element if one exists.
    ///
    /// :return: The `current` element or `nil` if the element does not exist.
    public func previous() -> Sequence.Generator.Element? {

        if currentIndex == self.prestartIndex {
            return nil
        }

        currentIndex = currentIndex.predecessor()

        if currentIndex != self.prestartIndex {
            self.current = seq[currentIndex]
        } else {
            self.current = nil
        }
        return self.current
    }

    public func generate() -> Self {
        self.previous()
        return self
    }
}

I don't have time to do a full pull request, but I believe this technique should enable you to use for scalar in buffer loops in all the various parsing functions; each new time you start to iterate through the JSON in one of the sub-parsers, there will implicitly be a call to generate() which will in turn automatically rewind the parsing by a character, revealing that lost character as the first item of iteration.

Here's a goofy example use from my testing, that just grabs the characters between paired brackets and adds them to an array:

var words: [String] = []
var unmatched: [String] = []

func parseBrackets(gen: RewindableGenerator<String.UnicodeScalarView>) {
    var sbuf = ""

    for (idx, c) in enumerate(gen) {
        if idx == 0 {
            if c == "[" {
                continue
            } else {
                // error or something
                return
            }
        }

        switch c {
        case "[":
            // nested brackets
            parseBrackets(gen)
        case "]":
            words.append(sbuf)
            return
        default:
            sbuf.append(c)
        }
    }
    unmatched.append(sbuf)
}


let s = "[This] [is ][a] weird [ne[st]e[d]] [\u{aaef}string!"
let g = RewindableGenerator(s.unicodeScalars)

for c in g {
    if c == "[" {
        parseBrackets(g)
    }
}

// words == ["This", "is ", "a", "st", "d", "nee"]
// unmatched == "ꫯstring!"

Performance

Number parsing performance is ok:

NSJONSerialization:
performance results: min: 10.716ms, max: 17.004ms, avg: 11.802ms

JSONLib:
performance results: min: 7.801ms, max: 20.115ms, avg: 8.418ms

From this file: https://github.com/chadaustin/sajson/blob/master/testdata/mesh.json

String parsing performance is terrible:

NSJONSerialization:
performance results: min: 4.687ms, max: 9.183ms, avg: 5.242ms

JSONLib:
performance results: min: 24.347ms, max: 36.947ms, avg: 26.928ms

From this file: https://github.com/chadaustin/sajson/blob/master/testdata/twitter.json

In addition to having an arbitrary depth limit, some of this needs to be revisited.

Conflict with JSValue in JavaScriptCore

Due to the apparent lack of keyed subscript support in Swift for Objective-C objects, I'm currently doing this:

let jsFunction = context.valueForKey("foo") as JSValue

In this case, JSValue is the type from JavaScriptCore.

As soon as I import JSONLib that same line won't compile because 'JSValue' is ambiguous for type lookup in this context.

Any advice on how to work around this?

How can I use this in my project?

I'm not terribly familiar with how to import libraries, especially with Swift. Cocoa pods made everything really easy. So who can I use this in my project?

Also, how can I get this into a playground?

Enhancement request to help with creating JSValues programmatically

extension JSValue {
    static func Array() -> JSValue {
        return JSValue(JSArrayType())
    }

    static func Object(minimumCapacity: Int = 8) -> JSValue {
        return JSValue(JSObjectType(minimumCapacity: minimumCapacity))
    }

    func append(value: JSValue) {
        if var array = self.array {
            array.append(value)
        }
    }
}

func +=(inout lhs: JSValue, rhs: JSValue) {
    lhs.append(rhs)
}

Usage:

// Making use of the JSON alias
var object = JSON.Object()
object["one"] = JSON(1)

var array = JSON.Array()
for index in 1...10 {
    array += JSON(index)
}

object["array"] = array

var root = JSON.Object()
root["object"] = object

Advice on referencing external values

When I try the following:

enum Foo: String {
    case Bar = "bar"
}
let array: JSON = [
    Foo.Bar.toRaw()
]

I get this error:

'Array<$T4>' is not convertible to 'JSON'

It seems reasonable to be able to do this - am I going about this the wrong way?

Stringify should escape double quotes

[ "url" : "should escape double quotes \"" ]
result in "{\"url\":should escape double quotes \"\"}"
should be "{\"url\":should escape double quotes \\\"\"}"

Inverted logic in assertions

I was going through the code, and I noticed that you're doing assert(true, "The JSON value is invalid"), but you probably mean assert(false) :)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.