BAD_INSTRUCTION within swift closure - closures

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?

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.

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;

Related

Access to key inside Dictionary get in Swift

Is it possible to access the key inside of a Dictionary get in Swift ?
The main idea is:
In this code
var _dict:[String:String] = [:]
var dict:[String:String] {
//get the key
return _dict
}
_dict = ["key 1":"Value 1","key 2":"Value 2"]
print(dict["key 1"])
Access the key to check if the value exists, if it exists return the value if not generate the value for that key
Did you know that Dictionary allows you to specify a default value in its subscript to avoid dealing with optional values. It works like so:
let dict = ["a": 1, "b": 2]
let c = dict["c", default: 3]
print(c) // 3
but that doesn't change the dictionary - it's still only has "a" and "b" keys, which is the expected behavior.
I think what you're asking about is whether it's possible to mutate the dictionary with a default value. The answer is yes - you could create a subscript with a mutating get.
But it's the wrong thing to do!
You will effectively have a getter with side-effects, which is typically a bad practice.
In any case, this is how you could implement a subscript with a new parameter setDefault:
extension Dictionary {
subscript(key: Key, setDefault defaultVal: #autoclosure () -> Value) -> Value {
mutating get {
if let val = self[key] {
return val
} else {
let val = defaultVal()
self[key] = val
return val
}
}
}
}
// dict needs to be a var now
var dict = ["a": 1, "b": 2]
let c = dict["c", setDefault: 3]
Now, this will mutate dict and it will be ["a": 1, "b": 2, "c": 3]

Removing NSNull from Key Path Results with Partial Matches

Given a data structure with mismatching objects:
1> import Foundation
2> let d: NSDictionary = ["test": [["name": "Dick", "age": 101], ["name": "Jane"]]]
valueForKeyPath: will return the values for the total number of sub-objects:
3> d.valueForKeyPath("test.name") as! NSArray
$R2: NSArray = "2 values" {
[0] = "Dick"
[1] = "Jane"
}
Even when the leaf key doesn't exist in all cases:
4> d.valueForKeyPath("test.age") as! NSArray
$R3: NSArray = "2 values" {
[0] = Int64(101)
[1] = {
NSObject = {
isa = NSNull
}
}
}
Is there some way to only get the existing ages, without an instances of NSNull?
#distinctUnionOfArrays and so on helps if there are multiple sub-objects without the leaf key, but you're still left with the one NSNull.
On a somewhat side note, if the leaf key is entirely unknown, then only NSNulls are returned:
5> d.valueForKeyPath("test.dog") as! NSArray
$R4: NSArray = "2 values" {
[0] = {
NSObject = {
isa = NSNull
}
}
[1] = {
NSObject = {
isa = NSNull
}
}
}
In contrast, if the root key is unknown, nil is returned:
6> d.valueForKeyPath("dog.name")
$R5: AnyObject? = nil
This logic strikes me as inconsistent, but perhaps I'm missing something?
var array:[AnyObject] = [1.1, 1.2, 1.3, 1.4, 1.5, 1.6, NSNull(),1.7, 1.8, 1.9]
let newArr = array.filter{ !($0 is NSNull) }
newArr
The second part of your question doesn't make sense to me:
This code:
let x = d.valueForKeyPath("dog.name")
Makes x an optional AnyObject?.
It returns nil with the key "dog.name" on your data. That's different than an array with nil/NSNULL entries.
If you try to force-unwrap it, it crashes:
let x = d.valueForKeyPath("dog.name") as! NSArray
If you want to get rid of the NSNull entries, use a filter:
let y = (d.valueForKeyPath("test.age") as? NSArray)?.filter{!($0 is NSNull)}
In the above code, I use as? to cast the result of valueForKeyPath to an array so it can return nil if the call does not return any results. (Otherwise it crashes.)
I then only call filter if the results are not nil.
Finally, I filter the array to only those objects that are not NSNull.
Note that y is an optional, and will be nil if d.valueForKeyPath("test.age") does not return a result.

iOS: Convert UnsafeMutablePointer<Int8> to String in swift?

As the title says, what is the correct way to convert UnsafeMutablePointer to String in swift?
//lets say x = UnsafeMutablePointer<Int8>
var str = x.memory.????
I tried using x.memory.description obviously it is wrong, giving me a wrong string value.
If the pointer points to a NUL-terminated C string of UTF-8 bytes, you can do this:
import Foundation
let x: UnsafeMutablePointer<Int8> = ...
// or UnsafePointer<Int8>
// or UnsafePointer<UInt8>
// or UnsafeMutablePointer<UInt8>
let str = String(cString: x)
Times have changed. In Swift 3+ you would do it like this:
If you want the utf-8 to be validated:
let str: String? = String(validatingUTF8: c_str)
If you want utf-8 errors to be converted to the unicode error symbol: �
let str: String = String(cString: c_str)
Assuming c_str is of type UnsafePointer<UInt8> or UnsafePointer<CChar> which is the same type and what most C functions return.
this:
let str: String? = String(validatingUTF8: c_str)
doesn't appear to work with UnsafeMutablePointer<UInt8>
(which is what appears to be in my data).
This is me trivially figuring out how to do something like the C/Perl system function:
let task = Process()
task.launchPath = "/bin/ls"
task.arguments = ["-lh"]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
var unsafePointer = UnsafeMutablePointer<Int8>.allocate(capacity: data.count)
data.copyBytes(to: unsafePointer, count: data.count)
let output : String = String(cString: unsafePointer)
print(output)
//let output : String? = String(validatingUTF8: unsafePointer)
//print(output!)
if I switch to validatingUTF8 (with optional) instead of cString, I get this error:
./ls.swift:19:37: error: cannot convert value of type 'UnsafeMutablePointer<UInt8>' to expected argument type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>')
let output : String? = String(validatingUTF8: unsafePointer)
^~~~~~~~~~~~~
Thoughts on how to validateUTF8 on the output of the pipe (so I don't get the unicode error symbol anywhere)?
(yes, I'm not doing proper checking of my optional for the print(), that's not the problem I'm currently solving ;-) ).

swift: changing dictionary values in an array that holds multiple maps

I am trying to do the following but seems to be not acceptable operation. Perhaps I am missing something fundamental in the language.
var foo:NSArray = []
var bar = ["name":"jake"]
foo = [bar]
foo[0]["name"] = "Fred"
The last line throws an error saying '#lvalue $T8' is not identical to 'AnyObject!' Is this sort of thing not allowed in swift? If so how do one go about achieving this.
You just have to declare foo the right way. As an Array of Dictionaries:
var foo:[[String:AnyObject]] = []
var bar = ["name":"jake"]
foo = [bar]
foo[0]["name"] = "Fred"
foo // [["name": "Fred"]]
When you dereference with foo[0] the return type is AnyObject. The type AnyObject does not have a subscript operator. Use
(foo[0] as! [String:String])["name"]
Or, if your array will only hold dictionaries, then define it with:
var foo : [[String:String]] = []
Here is an example:
$ swift
Welcome to Swift version 1.2. Type :help for assistance.
1> var foo : [[String:String]] = []
foo: [[String : String]] = 0 values
2> var bar : [String:String] = ["name":"jake"]
3.
bar: [String : String] = {
[0] = {
key = "name"
value = "jake"
}
}
3> foo = [bar]
4> foo[0]["name"]
$R0: String? = "jake"

How to unwrap NSMutableDictionary.allkeys in optional String Array

I am trying to get all the key values of NSMutableDictionary as String Array. I am using this myNSMutableDictionary.allkeys to get the values as an Array but I cannot find a way to unwrap the key values.
This is what I have tried so far:
for (key, _) in NSMutableDictionary {
println("THIS IS MY NEW KEY\(key)")
}
And I tried this
var myArray:NSArray = myNSMutableDictionary.allKeys
var string:NSString? = uniqueIDArray[0] as? NSString
println("This is unwraped value\(string!)")
And this
var myArray:Array = myNSMutableDictionary.allKeys
println("This is unwraped value\(myArray[0])")
I keep getting the value as Optional("kMSZgoTmiX") instead of kMSZgoTmiX which is the key value I need
Thank you for all your help!
So you've got a dictionary with values that are strings (and keys that are something, assume String):
var dictionaryOfStringValues : [String:String] = /* your dictionary */
And you want to iterate over the contents:
for (key, val) in dictionaryOfStringValues {
// use key and val
}
If you just want the values in a way you can easily iterate over:
var theValues = dictionaryOfStringValues.values
If you insist that theValues be an Array:
var theValuesAsAnArray = Array(dictionaryOfStringValues.values)
If you are starting with an NSMutableDictionary, then convert it at the point where it FIRST ENTERS your Swift code into a Swift Dictionary. Use an as variant to do that. After that, pure Swift.
Like this:
7> for (key, value) in ["a":1, "b":2] {
8. println (key)
9. println (value)
10. }
b
2
a
1
let myNSMutableDictionary = NSMutableDictionary()
myNSMutableDictionary["myKey1"] = 5
myNSMutableDictionary["myKey2"] = 10
myNSMutableDictionary["myKey3"] = 15
let myKeysArrayUnsorted = myNSMutableDictionary.allKeys as [String]
let myValuesArrayUnsorted = myNSMutableDictionary.allValues as [Int]
let keyString = myKeysArrayUnsorted[0] // "myKey2"
let keyValue = myNSMutableDictionary[keyString] as Int // 10
println("This is my first unsorted key \(keyString) = \(keyValue)")
let myKeysArraySorted = (myNSMutableDictionary.allKeys as [String]).sorted(<)
for key in myKeysArraySorted {
println(myNSMutableDictionary[key]!) // 5 10 15
}

Resources