-1

Simple example that I don't understand why is not working:

let f: Any = ["": 1]
if let f = f as? [String: Any] {
  "" // never enters
}

I'm trying to get this around my head, but don't understand why does this not work. I'm trying to work with numbers and bool, so won't to use anyobject due to the cast to nsnumber that both are redirected to and since I'm writing it in pure-swift for a school project I am not allowed to use that cast (JSON).

UPDATE

The project must handle JSON like SwiftyJSON library in GitHub, but without using AnyObject, ObjC or the NSNumber class.

Update 2

public struct JSON {

  public enum Type: Int {
    case Bool = 0
    case Number
    case String
    case Array
    case Dictionary
    case Null
  }

  var value: Any?
  var type: Type {
    switch value {
    case let value as Bool: return .Bool
    case let value as Number: return .Number
    case let value as String: return .String
    case let value as [Any]: return .Array
    case let value as [String: Any]: return .Dictionary
    default: return .Null
    }
  }

  init(_ value: Any?) {
    self.value = value
  }
}

let json = JSON([2])

This example falls in Null case

Jake Ortiz
  • 503
  • 9
  • 20

1 Answers1

1

In this case, the cast fails because f doesn't hold a [String:Any], it holds a [String:Int]

If you were to use this instead, it would do what you expect by first insuring that the dictionary is created as expected:

let any : Any = ["A":1] as [String:Any]

if let f = any as? [String: Any] {
    "" // enters now
}

For your edited (and really a completely different question) use an enum with associated values:

typealias JSONArray = [JSONValue]
typealias JSONObject = [String:JSONValue]

enum JSONValue {
    case Null
    case Boolean(Bool)
    case Number(Double)
    case Literal(String)
    case Array(JSONArray)
    case Object(JSONObject)

    static func with(b:Bool) -> JSONValue {
        return .Boolean(b)
    }

    static func with(d:Double) -> JSONValue {
        return .Number(d)
    }

    static func with() -> JSONValue {
        return .Null
    }

    static func with(s:String) -> JSONValue {
        return .Literal(s)
    }

    static func with(a:JSONArray) -> JSONValue {
        return .Array(a)
    }

    static func with(o:JSONObject) -> JSONValue {
        return .Object(o)
    }
}

This solves numerous problems for you, including having to use Any which is almost always a bad idea. Add whatever initializers you deem appropriate:

David Berry
  • 40,941
  • 12
  • 84
  • 95
  • It's a good solution but the problem is that in this case we know before hand that the object is a dictionary. In json the object could have any structure, not necessarily a dictionary – Jake Ortiz Mar 15 '15 at 18:26
  • I'm not sure what you're concern is. A JSON object is accurately represented by the swift type `[String:Any]` and a JSON array is `[Any]`. Ideally, since you don't have access to `NSObject` you'd actually define a an enum to represent `JSONValue` and probably even define type aliases for `JSONObject` and `JSONArray` `Any` should actually be avoided unless absolutely required, because it negates the type-safe features of Swift. – David Berry Mar 16 '15 at 05:15
  • In the case here, the if statement will only be true if any is a `[String:Any]` so only if it's a JSON dictionary. You could also test for `[Any]` to test for a JSON array, etc. – David Berry Mar 16 '15 at 05:16
  • I have tried making a complex jsonObject and casting it as Any, as it would arrive from a request. Then put it in a switch an use 'as' operator to [string: any], but it wouldn't fall into the case. – Jake Ortiz Mar 17 '15 at 01:42