1
func loadMe() -> Void {
    println(me.initUrl());

    let url:NSURL = NSURL(string:me.initUrl())
    let request:NSURLRequest = NSURLRequest(URL:url)
    let queue:NSOperationQueue = NSOperationQueue()

    NSURLConnection.sendAsynchronousRequest(request, queue:queue, completionHandler:{response, data, error in
        if data {
            var jerr:NSError?
            var json:NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options:NSJSONReadingOptions.MutableContainers, error:&jerr) as NSDictionary

            if !jerr {
                println(json.description)
                let time:String = json.valueForKey("time") as String
                println(time)

                //  self.me.setDictionary(json)
            }
        }
    })
}

The code above works fine up to the point where i want to assign a value from an NSDictionary to a variable.

let time:String = json.valueForKey("time") as String 

is followed by EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0) but

println(json.description) 

prints out a valid NSDictionary. Does anybody know a solution to this problem?

loopmasta
  • 1,693
  • 3
  • 14
  • 19

2 Answers2

2

The valueForKey() method returns an optional value; you are forcing that value to a String and apparently that is causing the crash. I can get the Swift REPL to crash with:

  1> var json = ["a": "1", "b": "2"]
json: Dictionary<String, String> = {
  [0] = {
    key = "a"
    value = "1"
  }
  [1] = {
    key = "b"
    value = "2"
  }
}
  2> let data:String = json["b"] as String
Bitcast requires both operands to be pointer or neither
  %58 = bitcast i8* %57 to %SS.232
Bitcast requires both operands to be pointer or neither
  %110 = bitcast i8* %109 to %SS.232
Stored value type does not match pointer operand type!
  store %SS.232 %110, i8** %.core7._baseAddress.value, align 8
 i8*LLVM ERROR: Broken function found, compilation aborted!
Assertion failed: (err == 0), function ~Mutex, file /SourceCache/lldb_KLONDIKE/lldb_KLONDIKE-320.3.100/source/Host/common/Mutex.cpp, line 246.
Abort trap: 6

The solution is to forgo the String coercion. In my example:

  2> let data:String? = json["b"]
data: String? = "2"

  3> let data:String? = json["c"]
data: String? = nil

I suspect you added the 'as String' 1) knowing that the value is actually a String and 2) to avoid a compiler error. The proper approach is to use ? to indicate an optional value.

GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • The difference with the original code is that NSJSONSerialization.JSONObjectWithData returns a AnyObject! wich i cast to a NSDictionary. I can not cast it to a Dictionary. The swift docs part for handling NSDictionary is missing and - let data:String? = json["time"] - does not compile. Cannot convert the expression's type 'AnyObject!' to type 'StringLiteralConvertible'. See https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/WorkingWithCocoaDataTypes.html – loopmasta Jun 04 '14 at 17:02
2

I solved my problem with casting to the correct type of the original NSDictionary value after i realised that not all values of the NSDictionary were NSStrings. If your service returns a mixed type JSON object like this

{"id":2, "name":"AC Vent Temp", ...}

you'll have to fetch it's values like that.

var id:int = sensor.valueForKey("id") as Int;
var name:String? = sensor.valueForKey("name") as String;
loopmasta
  • 1,693
  • 3
  • 14
  • 19