How are Int and String accepted as AnyHashable?
Consider that Optional
is an enum
, which is also a value type – and yet you're freely able to convert a String
to an Optional<String>
. The answer is simply that the compiler implicitly performs these conversions for you.
If we look at the SIL emitted for the following code:
let i: AnyHashable = 5
We can see that the compiler inserts a call to _swift_convertToAnyHashable
:
// allocate memory to store i, and get the address.
alloc_global @main.i : Swift.AnyHashable, loc "main.swift":9:5, scope 1 // id: %2
%3 = global_addr @main.i : Swift.AnyHashable : $*AnyHashable, loc "main.swift":9:5, scope 1 // user: %9
// allocate temporary storage for the Int, and intialise it to 5.
%4 = alloc_stack $Int, loc "main.swift":9:22, scope 1 // users: %7, %10, %9
%5 = integer_literal $Builtin.Int64, 5, loc "main.swift":9:22, scope 1 // user: %6
%6 = struct $Int (%5 : $Builtin.Int64), loc "main.swift":9:22, scope 1 // user: %7
store %6 to %4 : $*Int, loc "main.swift":9:22, scope 1 // id: %7
// call _swift_convertToAnyHashable, passing in the address of i to store the result, and the address of the temporary storage for the Int.
// function_ref _swift_convertToAnyHashable
%8 = function_ref @_swift_convertToAnyHashable : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in τ_0_0) -> @out AnyHashable, loc "main.swift":9:22, scope 1 // user: %9
%9 = apply %8<Int>(%3, %4) : $@convention(thin) <τ_0_0 where τ_0_0 : Hashable> (@in τ_0_0) -> @out AnyHashable, loc "main.swift":9:22, scope 1
// deallocate temporary storage.
dealloc_stack %4 : $*Int, loc "main.swift":9:22, scope 1 // id: %10
Looking in AnyHashable.swift, we can see the function with the silgen name of _swift_convertToAnyHashable
, which simply invokes AnyHashable
's initialiser.
@_silgen_name("_swift_convertToAnyHashable")
public // COMPILER_INTRINSIC
func _convertToAnyHashable<H : Hashable>(_ value: H) -> AnyHashable {
return AnyHashable(value)
}
Therefore the above code is just equivalent to:
let i = AnyHashable(5)
Although it's curious that the standard library also implements an extension for Dictionary
(which @OOPer shows), allowing for a dictionary with a Key
of type AnyHashable
to be subscripted by any _Hashable
conforming type (I don't believe there are any types that conform to _Hashable
, but not Hashable
).
The subscript itself should work fine without a special overload for _Hashable
keys. Instead the default subscript (which would take an AnyHashable
key) could just be used with the above implicit conversion, as the following example shows:
struct Foo {
subscript(hashable: AnyHashable) -> Any {
return hashable.base
}
}
let f = Foo()
print(f["yo"]) // yo
Edit: In Swift 4, both the aforementioned subscript overload and _Hashable
have been removed from the stdlib by this commit with the description:
We have an implicit conversion to AnyHashable, so there's no
need to have the special subscript on Dictionary at all.
Which confirms my suspicion.
Convert userInfo [AnyHashable: Any] to [String: Any]
For the following answer, the code is not tested against a compiler, there might be some typo issue that could be easily fixed, some of them are intentionally done to exergue the logic behind it, and not add with if let
/guard let
, as?
, etc. that are needed but add noise in the explanation.
I won't repeat @vadian answer, which is correct an explain why it fails.
So we are clear that dict["message"]
is a String
.
A piece of information that you seem to be missing in the JSON acronym is for what stands the "N": Notation.
When you printed dict["message"]
, you didn't have really a key/value object, you have a String representing a key-value object, but not in a Swift representation. You printed JSON Stringified (because it's clearly more readable that hex data JSON). If after the answer you print jsonDict
, you'll see that the output structure might be different.
So, as always, your basic tools are:
Data <== data(encoding:)/init(data:encoding:) ==> String
Data <== jsonObject(with:options:)/data(withJSONObject:options:) ==> Array or Dictionary //I bypass voluntarily the specific case of String at top level
Let's do it then!
let jsonStringifiedString = dict["message"] as String
let jsonStringifiedData = jsonStringifiedString.data(using: .utf8) as Data
let jsonDict = try JSONSerialization.jsonObject(with: jsonStringifiedData, options: []) as [String: Any]
let baseResponse = Mapper<NotificationModel>().map(JSON: jsonDict)
If I were you, I'd look into Mapper
if there is no way to do something like:
let baseResponse = Mapper<NotificationModel>().map(JSONData: jsonStringifiedData)
or
let baseResponse = Mapper<NotificationModel>().map(JSONString: jsonStringifiedString)
Because there are sometimes JSONStringified embedded in JSON, where you might need to call it on a String
or on a Data
directly.
Or just because the basic URLSession
request returns a Data
object in its closure, and you want to use it directly.
Looping an AnyHashable Dictionary
You can try
var element = dictionaryMessage!["precios"] as! [[String:Any]]
Binary operator '==' cannot be applied to operands of type '[AnyHashable : Any]?' and 'String'
As the error clearly states info
is a dictionary. You have to check if the dictionary contains the error key
if let error = info[PHImageErrorKey] as? String {
print(error)
// show an alert
} else {
thumbnail = result!
}
‘AnyHashable’ is not convertible to ‘NSObject’
Maybe you need to change your array type
var myMutableArray = [AnyHashable]()
to
var myMutableArray = [DCclass]()
And then in the for loop you can access it like this
for dc in myMutableArray {
print("DCclass.empName = \(dc.empName)")
}
Related Topics
Add Skreferencenode/Skscene to Another Skscene in Spritekit
Spritekit and Scenekit - How to Completely Pause a Game
Cross Platform Aes Encryption Between iOS and Kotlin/Java Using Apples Cryptokit
In Swift, How to Write a Generic Function to Resize an Array
Dynamic/Runtime Dispatch in Swift, or "The Strange Way Structs Behave in One Man's Opinion"
Is the Swift Divide "/" Operator Not Working or Have I Missed Something
Uitextview Change Text Color of Specific Text
Fatal Error: Array Index Out of Range in Swift Xcode6
Split Uint32 into [Uint8] in Swift
Enumerate Is Unavailable Call the Enumerate Method on the Sequence
Create an Outlet in Storyboard to an Inherited Property