how to convert __SwiftValue to Int or String from web3swift? - ios

I have data fetched from a network request, which is ["0": 1]. I want to parse the value 1 into either Int or String.
If I try to cast the value to either String, Int, NSNumber, or NSString, I invariably get the following error:
let value = data["0"] as! Int
Could not cast value of type '__SwiftValue' (0x7fff873c5bd8) to 'NSNumber' (0x7fff86d8c858).
or NSString.
When I checked:
let isValidJSON = JSONSerialization.isValidJSONObject(data)
this returns false, which means the following fails as well:
let json = try JSONSerialization.data(withJSONObject: data, options: .prettyPrinted)
How do I parse this?
I'm using a library named web3swift and the data is returned from this function:
public func call(transactionOptions: TransactionOptions? = nil) throws -> [String: Any] {
return try self.callPromise(transactionOptions: transactionOptions).wait()
}
And callPromise in turn returns the following:
public func callPromise(transactionOptions: TransactionOptions? = nil) -> Promise<[String: Any]>

I digged into the library's code, and found that the library decodes the integers in the response as either BigInt or BigUInt. You should know which kind of data you are expecting.
You should try casting to one of those types instead, and since BigInt or BigUInt can store numbers that are arbitrarily big, you probably shouldn't convert them to an Int. You can convert them to Strings (not sure why you want to) using String.init(_:).
This is not one of the types of object that JSONSerialization recognises, so JSONSerialization.isValidJSONObject returns false.

Related

Parse an object returned as JSON from API in swift

I have recieved a response object (res) in swift from REST API. It is of type. __NSArrayM. It contains a JSON format string which I want to parse.
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It is a long JSON String and I have shortened it for simplicity.
To parse a json, the object needs to be of type Dictionary but I can't cast the object of type __NSArrayM into it.
I searched a lot but can't figure out anyway to read this JSON string.
Additional: Whichever object I try to cast the response object. I get the error -
Could not cast value of type '__NSArrayM' (0x107e86c30) to 'NSData' (0x107e86168) or whichever data type I cast into.
Let's do this step by step.
You say you have an object named "res" which is of type __NSArrayM and which contains this thing:
{ JsonResult = "[ { \"IsAuth\":\"true\" } ]"; }
It means that you already have converted the JSON to an object, namely an NSArray.
In this array that we don't see, this thing you're showing us is a dictionary (that we will name "dict") with its value being a String which itself represents another JSON object.
Let's get the value using the key:
if let value = dict["JsonResult"] as? String {
print(value)
}
Now "value" is supposed to be "[ { \"IsAuth\":\"true\" } ]".
This is a String which represents JSON. To decode the JSON, we first have to make the string into data then we can decode:
if let data = value.data(using: .utf8) {
if let content = try? JSONSerialization.jsonObject(with: data, options: []),
let array = content as? [[String: Any]]
{
print(array)
}
}

swift 3, JSON, invalid top-level type when writing

I have two exactly json objects, one is created from a function, the other is hard-coded, the hardcoded one works, the other doesn't (it always complains about the error invalid top-level type , which is weird. Any tip? Tks
let myData = self.dailyMileage?.toDictionary()
let directData = ["orgId" : self.orgId, "driverId" : self.driverId, "date" : Utils.getTodaysDate() ] as [String : Any]
//this won't work unless I substitute myData with directData
let jsonData = try JSONSerialization.data(withJSONObject: myData, options: .prettyPrinted)
//this is the function that produces myData, and nothing is nil
public func toDictionary() -> [String : Any] {
let dict = [ "orgId" : orgId , "driverId": driverId, "date" : date] as [String : Any]
return dict
}
JSONSerialization as given in the documentation:
An object that may be converted to JSON must have the following properties:
The top level object is an NSArray or NSDictionary. All objects are instances of NSString, NSNumber, NSArray, NSDictionary, or NSNull.
All dictionary keys are instances of NSString. Numbers are not NaN or infinity.
Other rules may apply. Calling isValidJSONObject(_:) or attempting a conversion are the definitive ways to tell if a given object can be converted to JSON data.
I think the one that's coming from the function might have an NSDate object instead of an NSString object.
The other reason is because your myData object is optional. JSONSerialization may give an error like that is the object is optional.
Please check if it is due to one of those two reasons. Feel free to suggest edits to make it better.

Core Data and making double from type AnyObject? Swift

I was writing a code for CoreData. My datamodel includes name and moneyAmount. Here's the part of the code I have troubles with
do {
let request = NSFetchRequest(entityName: "MoneyData")
let results = try context.executeFetchRequest(request)
if results.count > 0 {
for item in results as! [NSManagedObject] {
let name = String(item.valueForKey("name"))
let moneyAmount = item.valueForKey("moneyAmount")
moneyManager.addMoney(name, moneyAmount: moneyAmount)
}
}
} catch {
print("There was an error saving data")
}
Now the problem is that my moneyManager.addMoney requires String and Double. However, with this code, the error that I get is:
Optional Chain has no effect, already produces 'Anyobject?'
Cannot convert value of type AnyObject? to expected argument type 'Double'
I don't really understand what it means by Anyobject. I think I should convert anyobject to double to make it work right?
Thanks in advance
valueForKey() returns an object of type AnyObject because there's no way of knowing at compile-time what type of object it's referencing. You can cast to a specific type using as. For example, moneyAmount as? Double will result in an object of type Double?, either containing the numeric value, or being nil if the object wasn't of type Double.

Cast from '()' to unrelated type 'String' always fails

I'm trying to step through an [AnyObject] array from a completion block and cast the items as Strings so that I can then put them in a tableView. However, when I try to append the individual values of the array I get this error: Cast from '()' to unrelated type 'String' always fails. Here is the code:
client.historyForChannel(ids, start: nil, end: nil, withCompletion: { (result, status) -> Void in
if status == nil {
if result!.data.messages.count > 0 {
let historyMessages = result!.data.messages as? [String]
for value in historyMessages!{
self.messagesArray.append(value) as? String //error
}
}
}
})
If it helps, I'm using PubNub to create/store messages in my Swift app.
Thanks!
When you wrote
self.messagesArray.append(value) as? String
you probably meant
self.messagesArray.append(value as? String)
although
self.messagesArray.append(value)
should suffice because historyMessages is already of type [String]!.
The error is saying that you are casting the result of self.messagesArray.append(value) (which is Void because append does not return anything) to String, which does always fail.
As an aside, your code uses way more exclamation points than it should. You should be using guard-let to make sure your variables are non-nil.

How to cast Dictionary in Swift to related type?

This is what I am trying to do with the dictionary:
if let deliveries = dictionary["deliveries"] as? NSDictionary {
var castedDeliveries = [Double: Double]()
for delivery in deliveries {
if let value = delivery.value as? Double {
castedDeliveries[Double(delivery.key as! NSNumber)] = value //Could not cast value of type 'NSTaggedPointerString' (0x1a1e3af20) to 'NSNumber' (0x1a1e458b0).
}
}
settings!.deliveries = castedDeliveries
}
And this is what I try to cast, as a part of JSON response from server:
deliveries = {
2 = 0;
5 = "2.59";
7 = "3.59";
};
It doesnt work, because there is an error at commented line:
Could not cast value of type 'NSTaggedPointerString' (0x1a1e3af20) to 'NSNumber' (0x1a1e458b0).
You are trying to cast dictionary directly but instead you need to cast each key - value pair. If you want generic solution to this problem take a look at SwiftyJSON library which address JSON parsing problem for you.
Casting doens't mean data transformation from a type to another.
Your dictionary seems to be composed by Integer keys and String values.
If you want to transform in something else you ca use the map function.
let converted = deliveries.map{[Double($0) : Double($1)]}
But pay attention.
Here we are saying, iterate over the dictionary (in the $0 there is the dictionary key in the $1 there is the value) and create a new dictionary that has as a key a Double initialized at the key value and as a new value a Double initialized as the old dictionary value. The last conversion can fail, so the returned data is an optional.
As I noted in the comments, this isn't casting. You want a data conversion. You need to do that explicitly, especially in this case since it might fail.
Looking at the error, I think you really have a dictionary of [String:String] here (in NSDictionary form). That suggests the JSON is badly encoded, but such is life. Assuming that dictionary looks something like this:
let dictionary: NSDictionary = ["deliveries": ["2":"0", "5": "2.59", "7": "3.59"]]
You would convert it to [Double:Double] like this:
if let jsonDeliveries = dictionary["deliveries"] as? [String:String] {
var deliveries: [Double: Double] = [:]
for (key, value) in jsonDeliveries {
if let keyDouble = Double(key),
valueDouble = Double(value) {
deliveries[keyDouble] = valueDouble
}
}
// Use deliveries
}
This silently ignores any values that can't be converted to Double. If you would rather generate errors, use a guard let rather than an if let.

Resources