Error in adding an element to [String:Array<NSDictionary>] in Swift - ios

I have a property in my model of Type : [String:Array<NSDictionary>].
I want to add elements to this, in a loop. So this is what I do :
for var k=0;k<body.count;k++ {
var dict=body[k] as NSDictionary
if(k==0) {
self.model.data[i]!=[dict]
}
else {
self.model.data[i]!.append(dict)
}
}
When I do this, I get the following error :
fatal error: unexpectedly found nil while unwrapping an Optional value
The constructor initializes model.data to data=[String:Array<NSDictionary>]().
Please Help. Thanks in advance.

The problem is probably that you are unwrapping self.model.data[i] when you assign [dict] to it. I assume you are doing that in the case where data[i] has no value yet. So the forced unwrap will result in a nil pointer, which causes a crash.
Try this:
for var k=0;k<body.count;k++ {
var dict=body[k] as NSDictionary
if(k==0) {
self.model.data[i]=[dict]
}
else {
self.model.data[i]!.append(dict)
}
}
Although this assumes that self.model.data[i] exists for the case where k is not equal to 0. I am not sure if that is correct, you don't provide enough details.
What I think you are trying to do is this:
for var k = 0; k < body.count; k++ {
var dict = body[k] as NSDictionary
if self.model.data[i] == nil {
self.model.data[i] = []
}
self.model.data[i]!.append(dict)
}

Related

Swift, EXC_BAD_Instruction

My program should fitch the data from an array, and put it in a tableView
var rideTime: String!
var rideLocation: String!
var RideDriver: String!
rideTime = RidestList[indexPath.row].TimeX!
rideLocation = RidestList[indexPath.row].LocationX!
RideDriver = RidestList[indexPath.row].DriverNameX!
cell.DriverX.text = rideTime;
cell.TimeX.text = rideLocation;
cell.LocationX.text = RideDriver;
return cell
In the cell.DriverX.text=rideTime it gives me EXC_BAD_Instraction
And a "atal error: unexpectedly found nil while unwrapping an Optional value
(lldb) " error appears, can anyone help?
if let ride_time = RidestList[indexPath.row].TimeX
{
cell.DriverX.text = ride_time
}
if let ride_location =RidestList[indexPath.row].LocationX
{
cell.TimeX.text = ride_location
}
if let river_driver =RidestList[indexPath.row].DriverNameX
{
cell.LocationX.text = river_driver
}
this could help you with your problem
The crash is basically due to no value coming to your variable rideTime. Best practice is use of optional binding var rideTime: String? to the variables which can expect null values. This will restrict the crash that you faced.

If let condition true when value is missing in optional type, swift

I have parser in Objc, parser returns NSDictionary. I am using this parser in swift class. But when some value is missing on that dictionary, it shows nil value. e.g. ->
wirlessData = {
"anon" = {
};
"channel" = {
"text" = 1;
};
}
I am checking through
if let wepauthValue = wirlessData["wepauth"] {
if let value = wepauthValue["text"] {
print("\(value)") // nil
}
}
I don't how it satisfy the if let condition. Any one faced this types of problem can help me out.
Thanks,
vikash
You don't need any special code to do this, because it is what a dictionary already does. When you fetch dict[key] you know whether the dictionary contains the key, because the Optional that you get back is not nil (and it contains the value).
So, if you just want to answer the question whether the dictionary contains the key, ask:
let keyExists = dict[key] != nil
If you want the value and you know the dictionary contains the key, say:
let val = dict[key]!
But if, as usually happens, you don't know it contains the key - you want to fetch it and use it, but only if it exists - then use something like if let:
if let val = dict[key] {
// now val is not nil and the Optional has been unwrapped, so use it
}
I have tested it and found that value is still optional.Take a look at screenshot below to understand it better.
"anon" would be an empty dictionary. An empty dictionary is not nil, it is a dictionary. Just an empty one. A JSON parser will never, ever give nil values unless you ask for a key that is not in a dictionary. For example wirlessData ["nonexistingkey"] would give you nil.
If you be more type-strong about it with the if..let's then:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? String {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match string at all")
}
}
or even more specifically in your case:
if let anonValue = wirlessData["anon"] {
if let value = anonValue["text"] as? Int {
// This won't execute if value isn't converted from `anonvalue["text"]` to String specifically. This includes null been a false match too
print("\(value)") // nil
}else{
print("Value did't match int at all")
}
}
The value your parser is returning not nil, its empty so you need to check on count if inner data type is dictionary or array, I have past 1 sample here
Please use below code and correct your logic accordingly to get it work properly
let wirlessData:[String:AnyObject] = [
"anon" : [],
"channel" : [
"text" : 1
]
]
if wirlessData["anon"]?.count > 0 {
if let value = wirlessData["anon"]!["text"] {
print("\(value)") // nil
}
}
Try this below code using type check operator (is) -
if wirlessData["anon"] is [String:AnyObject]
{
let anon = wirlessData["anon"]!
print(anon)
if anon["random"] is String {
let stringValue = anon["random"]!
print("\(stringValue)")
}
else if anon["random"] is Int
{
let intValue = anon["random"]!
print("\(intValue)") // nil
}
else
{
print(" may be value did't match string & Int or nil ")
}
}

Multidimensional Array Unwrapping an Optional

so I'm having this problem where I can't unwrap an optional for outputting it into the label, I've even tried just printing it in the console and it still gives me an optional
The code and array are in different files.
Code It's in a VC:
for var i = 0; i < stateName.count; i++ {
if tax.state == stateName[i][0] {
stateName[i][1] = Double(taxNumb.text!)!
print(stateName[i][1])
output.text = String(stateName[i][1])
}
}
Array Code I made this in an empty swift file:
var tax : Taxes? = nil
var stateName = [
["AK - Alaska", tax?.alaska!],
["AL - Alabama", tax?.alabama!],
["AR - Arkansas", tax?.arkansas!],
["AZ - Arizona", tax?.arizona!],
["CA - California", tax?.california!]
]
As I wrote in my comment to your previous question use the "Nil Coalescing" ?? operator:
output.text = String(stateName[i][1] ?? "not set")
Or using the alternate swift String magic
output.text = "\(stateName[i][1] ?? "not set")"
The operator returns the first value if it not nil, otherwise it returns the second value.

swift ios: different errors for similar data .. very strange

Something strange is happening.
I have this in my TableDataArray:
(
{
count = 0;
title = Open;
},
{
count = 20;
title = Closed;
},
{
count = 0;
title = Pending;
},
{
count = 10;
title = Queue;
}
)
When I do just:
var rowData: NSDictionary = TableDataArray[indexPath.row] as NSDictionary
var maintext: String? = rowData["title"] as NSString
println(maintext)
if (maintext != nil ){
cell.textLabel.text = maintext
}
it works, I see the titles in my table.
But as soon as I add these lines:
var detailtext: String? = rowData["count"] as NSString ## tried also as Int, NSInteger, similar fate
println(detailtext)
if (detailtext != nil) {
cell.detailTextLabel.text = detailtext
}
The app crashes with "Swift dynamic cast failed", and I am unable to figure out why.
Another is if I make another API call, and there, the results are similar, but instead of crashing, it just displays... both the text and detailtext.
Yet in another api call, it crashes, but with 'fatal error: unexpectedly found nil while unwrapping an Optional value'... and yet in another one, it simply says String is not convertible to Uint8...
And this is bugging me. Same API calls, similar results, but it works in one, and crashes with different results...
So question is, how do I detect and troubleshoot such issues, and then display the detailText... because the values are there.
Thanks.
Your value can't be an Int or a String because values in NSDictionarys have to be objects. Your count is an NSNumber which is an object wrapper around a basic number type.
To safely extract the number from your NSDictionary use this style:
if let count = rowData["count"] as? NSNumber {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
cell.detailTextLabel.text = "\(count)"
}
This protects you from a whole host of problems. When you ask for an item from an NSDictionary, it is possible the key doesn't exist in the dictionary, and in that case the result will be nil. If you attempt to cast this directly to an expected type, you will get the fatal error: unexpectedly found nil while unwrapping an Optional value message. With the above style, the nil is handled gracefully and no error results, you just don't enter the block.
It appears that your count can have various types. You can use a switch to handle this in a cleaner way:
switch rowData["count"] {
case let count as NSNumber:
cell.detailTextLabel.text = "\(count)"
case let count as NSString:
cell.detailTextLabel.text = count
case nil:
println("value not in dictionary")
default:
println("I still haven't identified the type")
}
This worked:
if let maintext = rowData["title"] as? NSString {
println(maintext)
cell.textLabel.text = maintext
}
if var count = rowData["count"] as? NSNumber {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
println("\(count)")
cell.detailTextLabel.text = "\(count)"
}
if var count = rowData["count"] as? String {
// If I get here, I know count is an NSNumber. If it were some other type
// it wouldn't crash, but I wouldn't get to this point.
println(count)
cell.detailTextLabel.text = count
}
But is this correct way ?

Detect a Null value in NSDictionary

I have an NSDictionary that's populated from a JSON response from an API server. Sometimes the values for a key in this dictionary are Null
I am trying to take the given value and drop it into the detail text of a table cell for display.
The problem is that when I try to coerce the value into an NSString I get a crash, which I think is because I'm trying to coerce Null into a string.
What's the right way to do this?
What I want to do is something like this:
cell.detailTextLabel.text = sensor.objectForKey( "latestValue" ) as NSString
Here's an example of the Dictionary:
Printing description of sensor:
{
"created_at" = "2012-10-10T22:19:50.501-07:00";
desc = "<null>";
id = 2;
"latest_value" = "<null>";
name = "AC Vent Temp";
"sensor_type" = temp;
slug = "ac-vent-temp";
"updated_at" = "2013-11-17T15:34:27.495-07:00";
}
If I just need to wrap all of this in a conditional, that's fine. I just haven't been able to figure out what that conditional is. Back in the Objective-C world I would compare against [NSNull null] but that doesn't seem to be working in Swift.
You can use the as? operator, which returns an optional value (nil if the downcast fails)
if let latestValue = sensor["latestValue"] as? String {
cell.detailTextLabel.text = latestValue
}
I tested this example in a swift application
let x: AnyObject = NSNull()
if let y = x as? String {
println("I should never be printed: \(y)")
} else {
println("Yay")
}
and it correctly prints "Yay", whereas
let x: AnyObject = "hello!"
if let y = x as? String {
println(y)
} else {
println("I should never be printed")
}
prints "hello!" as expected.
You could also use is to check for the presence of a null:
if sensor["latestValue"] is NSNull {
// do something with null JSON value here
}
I'm using this combination and it also checks if object is not "null".
func isNotNull(object: AnyObject?) -> Bool {
guard let object = object else { return false }
return isNotNSNull(object) && isNotStringNull(object)
}
func isNotNSNull(object: AnyObject) -> Bool {
object.classForCoder != NSNull.classForCoder()
}
func isNotStringNull(object: AnyObject) -> Bool {
guard let object = object as? String where object.uppercaseString == "NULL" else {
return true
}
return false
}
It's not that pretty as extension but work as charm :)
NSNull is a class like any other. Thus you can use is or as to test an AnyObject reference against it.
Thus, here in one of my apps I have an NSArray where every entry is either a Card or NSNull (because you can't put nil in an NSArray). I fetch the NSArray as an Array and cycle through it, switching on which kind of object I get:
for card:AnyObject in arr {
switch card { // how to test for different possible types
case let card as NSNull:
// do one thing
case let card as Card:
// do a different thing
default:
fatalError("unexpected object in card array") // should never happen!
}
}
That is not identical to your scenario, but it is from a working app converted to Swift, and illustrates the full general technique.
my solution for now:
func isNull(someObject: AnyObject?) -> Bool {
guard let someObject = someObject else {
return true
}
return (someObject is NSNull)
}
tests look good so far...
I had a very similar problem and solved it with casting to the correct type of the original NSDictionary value. 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;
This did solve my problem. See BAD_INSTRUCTION within swift closure

Resources