I can't find a clue to add a new value to an Encodable object and then return the result as Encodable object again, as follows:
func add(pageNumber: Int, toParams params: Encodable? = nil) -> Encodable {
var parameters: [String: Any] = [:]
if let params = params {
let jsonEncoder = JSONEncoder()
if let jsonData = try? jsonEncoder.encode(params),
let jsonObject = try? JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
parameters = jsonObject
}
}
parameters["page"] = pageNumber
return parameters
}
I need the input params to be Encodable (as in the code snippet above) and not [String:Any] as it may hold objects of different types, one of them and not limited to, is a [String:Any] dictionary.
And in case there're no input params to the function, it should return an Encodable [String: Any] dictionary that holds pageNumber.
Related
Tried this, but get error:
var d = (try JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.mutableContainers)) as [String: String]
guard let d2 = d else {
return
}
You can try
guard let dic = try? JSONSerialization.jsonObject(with: data) as? [String: String] else { return }
The right tool here is JSONDecoder, not JSONSerialization:
let d = try JSONDecoder().decode([String: String].self, data)
.mutableContainers doesn't make sense when converting to a Swift Dictionary. That causes it to create NSMutableDictionary objects, which will just be converted to [String: String] exactly the same as without .mutableContainers (but possibly with an extra copy step).
I'm working on a pet project where I am serializing JSON using the JSONSerialization class and jsonObject(with:options:). The object is unusable until cast into a Dictionary [String: Any] or an Array [Any]. This is where the inconsistency occurs. The following is a method from one of my classes. The input is tested and valid.
private static func parse(data: Data) -> [JSONDictionary]? {
do {
let options = JSONSerialization.ReadingOptions() // rawValue = UInt 0
let otherOptions: JSONSerialization.ReadingOptions = [] // rawValue = UInt 0
let jsonAny = try JSONSerialization.jsonObject(with: data, options: otherOptions)
if let array = jsonAny as? [String: Any] {
print(array)
}
} catch {
return nil
}
return nil
}
Both of the ReadingOption objects are valid and produce valid output that can be properly cast, and print(array) is called.
However, when I use the following, invalid output is returned and can not be cast properly. Note options in the jsonObject call has an equivalent value to otherOptions in the above example.
private static func parse(data: Data) -> [JSONDictionary]? {
do {
let jsonAny = try JSONSerialization.jsonObject(with: data, options: [])
if let array = jsonAny as? [String: Any] {
print(array) // never called
}
} catch {
return nil
}
return nil
}
I thought because they have equivalent values that I could use them in place of each other. But that is not the case. Is this a bug, or am I using this incorrectly?
Edit: here is the dataset being used https://www.govtrack.us/api/v2/role?current=true&role_type=senator
The reading options are irrelevant. In Swift ReadingOptions are only useful if the expected result is not array or dictionary.
If the expected type is array or dictionary omit the options parameter.
The inconsistency is that your return type is an array ([JSONDictionary]) but the actual type is a dictionary.
private static func parse(data: Data) -> JSONDictionary? {
do {
let jsonAny = try JSONSerialization.jsonObject(with: data)
if let jsonDictionary = jsonAny as? JSONDictionary {
return jsonDictionary
}
} catch {
print(error)
return nil
}
return nil
}
It's recommended to hand over an error of a throwing method
enum SerializationError : Error {
case typeMismatch
}
private static func parse(data: Data) throws -> JSONDictionary {
let jsonAny = try JSONSerialization.jsonObject(with: data)
guard let jsonDictionary = jsonAny as? JSONDictionary else { throw SerializationError.typeMismatch }
return jsonDictionary
}
I am trying to extend Dictionary with the following code:
extension Dictionary where Key: ExpressibleByStringLiteral, Value: AnyObject {
var jsonString: String? {
if let dict = (self as AnyObject) as? Dictionary<String, AnyObject> {
do {
let data = try JSONSerialization.data(withJSONObject: dict, options: JSONSerialization.WritingOptions(rawValue: UInt.allZeros))
if let string = String(data: data, encoding: String.Encoding.utf8) {
return string
}
} catch {
print(error)
}
}
return nil
}
}
Where I write something like:
let x: [String: String] = ["": ""]
x.jsonString
I get this error:
Value of type '[String: String]' as no member 'jsonString'
Anything I am missing?
There is no need to constrain Dictionary Value type at all:
extension Dictionary where Key: ExpressibleByStringLiteral {
var jsonString: String? {
guard let data = try? JSONSerialization.data(withJSONObject: self)
else { return nil }
return String(data: data, encoding: .utf8)
}
}
Since String is a value type , look for it's
public struct String {
and AnyObject refers to any instance of a class only , and is equivalent to id in Objective-C , so this declaration of x
[String: String] doesn't fit with [String: AnyObject]
because Any refers to any instance of a class, struct, or enum so it'll fit perfectly
This question already has answers here:
Optional binding with try? and as? still produces an optional type
(2 answers)
Closed 5 years ago.
Language Used: Swift 3
Xcode Version: 8.3.2 (8E2002)
I have an extension on Data which parses the data into a JSONObject of type Any
extension Data {
func toJsonObject() -> Any? {
do {
return try JSONSerialization.jsonObject(with: self, options: [])
} catch {
print(error)
}
return nil
}
}
Now the weird thing is when I use guard the result object seems to be different when using toJsonObject() and try?
For example
guard let dictionary = data.toJsonObject() as? [String: Any] else {
return
}
dictionary is now of type [String: Any]
Whereas when I use this:
guard let dictionary = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
return
}
dictionary is now of type [String: Any]?
Isn't the result of the second code block supposed to be [String: Any] instead of the optional [String: Any]?
Is this a mistake on Swift or am I doing something wrong?
This is a feature of Swift, I'd say. The use of try? means that this becomes a double optional, it's trying to decode straight to that casting of as? [String: Any]. Plug this in and check the type on this to see the double optional in action:
// Becomes a type of `[String : Any]??`
let dictionary = try? JSONSerialization.jsonObject(with: Data(), options: []) as? [String: Any]
I think the answer you want is to just add some parentheses to clarify your intent:
guard let dictionary = (try? JSONSerialization.jsonObject(with: Data(), options: [])) as? [String: Any] else {
return
}
I cant able to convert result into IeroLocationSave object. This below cod e says -- cannot convert value of any to IeroLocationSave type in coercion
var model = IeroLocationSave!.self
libName.fetchDataUsingPost(forURL: url, parameters: parameters, headerFiled: [:], completionHandler: {(result: Any?)-> Void in
let json = result
print("json value",json!)
model = result! as IeroLocationSave
print("actualResponse",result as? [String: AnyObject])
// guard let json = result as? [String: AnyObject] else{∫
// }
}, failureHandler: {(result: Error?)-> Void in
print("error", result ?? "nil")})