Using key of a dictionary on another dictionary crashes - swift

Following code fails with an error on xcode playground. Couldn't understand the reason why. This was tried in XCode 9.3.
Fatal error: Unexpectedly found nil while unwrapping an Optional value on line if (value as! String) != (dictionary[key] as! String) {. Here key is x, dictionary[key] is nil, whereas the dictionary has a key with x.
//: Playground - noun: a place where people can play
import UIKit
extension Dictionary {
func isSubDictionary(of dictionary: [AnyHashable: Any]) -> Bool {
var fail = false
outerloop: for (key, value) in self {
switch value {
case is Int:
if (value as! Int) != (dictionary[key] as! Int) {
fail = true
break outerloop
}
case is Double:
if (value as! Double) != (dictionary[key] as! Double) {
fail = true
break outerloop
}
case is String:
if (value as! String) != (dictionary[key] as! String) {
fail = true
break outerloop
}
default:
break
}
}
return !fail
}
}
let v: [AnyHashable: Any] = ["x": "y"]
let u: [AnyHashable: Any] = ["x": "y", "z": "u"]
print("\(v.isSubDictionary(of: u))\n")

You have added isSubDictionary as an extension to Dictionary, so the type of self is Dictionary<Key, Value>, not Dictionary<AnyHashable, Any>. This means that the keys of self and of dictionary are not the same.
A value of type AnyHashable hides, but still knows, the type is it wrapping. When you write:
dictionary[key]
key is wrapped in an AnyHashable but the type that is being wrapped is Key. So when it is used as a key to dictionary, the wrapped type Key does not match the wrapped types in this second dictionary’s keys. You can see this with:
print("\(dictionary.keys.contains(self.keys.first!))") // prints false
If your intent is that the two dictionaries are of the same type, then make the function:
func isSubDictionary(of dictionary: [Key: Any]) -> Bool

Related

Assertion Failure on getting a key from NSDictionary in Swift

I'd like to understand how could the function below sometimes generates a Swift "_assertionFailure" in line:
if let s = dict![key] as? String
I suppose that if dict![key] is not found, a nil would return, so the if let would get a nil value and the condition would fail, with no errors, no assertions. Where I am getting wrong?
func getDictKey(_ dict: NSDictionary?, key: String) -> String?
{
var value: String?;
if (dict != nil && !key.isEmpty)
{
if let s = dict![key] as? String {
value = s;
}
}
return value;
}
Your syntax is very, very objective-c-ish.
In Swift you can simply write
func getDictKey(_ dict: NSDictionary?, key: String) -> String?
{
return dict?[key] as? String
}
It contains all checks except the empty string check. The question mark after dictaborts the chain if the dictionary is nil.
You should not use NSDictionary in Swift but a more meaningful naming
func getValue(from dict: [String:Any]?, forKey key: String) -> String?
{
return dict?[key] as? String
}

cannot subscript a value of type 'Dictionary<Key, Value>' with an index of type 'String' self[key]

I have Dictionary of type Dictionary (Key, Value). When I am trying to access the value it's giving the error:
cannot subscript a value of type 'Dictionary' with an index of type 'String' self[key]
My Class.
extension Dictionary where Key == String {
public func optionalValue<T>(_ key: String) throws -> T?
{
guard let value = self[key],
!(value is NSNull) else { return nil }
guard let typedValue = value as? T else { throw JSONParserError.invalidValue(key: key, value: value) }
return typedValue
}
}
The following built from your question above compiles and works fine for me in a playground using Xcode 10.2.
import Foundation
extension Dictionary where Key == String {
public func optionalValue<T>(_ key: String) throws -> T? {
guard let value = self[key] else { return nil }
guard !(value is NSNull) else { return nil }
guard let typedValue = value as? T else { throw NSError() }
return typedValue
}
}
var dictionary = [String:Any]()
dictionary["nullKey"] = NSNull()
dictionary["intKey"] = 12345
var value: Int?
value = try dictionary.optionalValue("nullKey")
value = try dictionary.optionalValue("intKey")
The line value = try dictionary.optionalValue("nullKey") outputs nil as expected and value = try dictionary.optionalValue("intKey") outputs 12345.
So to answer your question it should work fine.
I got the issue. Actually in my case the code was something like that
var dictionary = [String:AnyObject]()
So When It was getting Int value it was throwing Error.
This solved the issue.
var dictionary = [String:Any]()

Swift generic bool casting different from direct casting

let dic: [String: Any] = [
"b": true
]
func cast<T>(value: Any, to type: T) -> T? {
return value as? T
}
let value = dic["b"]!
let casted = cast(value: value, to: Bool.self)
print(casted.debugDescription) // nil
print(value as! Bool) // true
I'm doing dynamic casting using generic function, the results are different from direct casting when the value is Bool, why?
You need to pass the type correctly as below,
func cast<T>(value: Any, to type: T.Type) -> T?
OR
You can remove passing the type as below,
func cast<T>(value: Any) -> T? {
return value as? T
}
let casted: Bool? = cast(value: value)

How to compare "Any" value types

I have several "Any" value types that I want to compare.
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
print(any1 == any2)
print(any2 == any3)
print(any3 == any4)
Using the == operator shows an error:
"Binary operator '==' cannot be applied to two 'Any' (aka
'protocol<>') operands"
What would be the way to do this ?
The only way to do this is with a function other than == that takes a type parameter, and then compares the values if they are both of that type:
func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool {
guard let a = a as? T, let b = b as? T else { return false }
return a == b
}
Now, using your variables above, you can compare them like this:
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
isEqual(type: Int.self, a: any1, b: any2) // true
isEqual(type: Int.self, a: any2, b: any3) // false
isEqual(type: String.self, a: any3, b: any4) // true
You can do it like this by using AnyHashable:
func equals(_ x : Any, _ y : Any) -> Bool {
guard x is AnyHashable else { return false }
guard y is AnyHashable else { return false }
return (x as! AnyHashable) == (y as! AnyHashable)
}
print("\(equals(3, 4))") // false
print("\(equals(3, equals))") // false
print("\(equals(3, 3))") // true
As not every Equatable has to be Hashable, this might fail under rare circumstances.
Usually there is no reason for using above hack; but sometimes you will need it, just as sometimes AnyHashable is needed.
To use == operator, type has to conform to Equatable protocol. Any protocol does not conform to Equatable protocol, so there is no way to compare two Any values. It's logical - Any is too broad term - values can have no 'common denominator'.
What's more, Swift doesn't allow to compare two Equatable values which have different type. E.g. both Int and String conform to Equatable but 1 == "1" does not compile. The reason for that is the declaration of == in Equatable protocol: func ==(lhs: Self, rhs: Self) -> Bool. This Self basically means that both arguments have to have the same type. It it's kind of a placeholder - in implementation for specific type, Self should be replaced with the name of this type.
Aaron Rasmussen's answer can also be used as an extension, like so:
public extension Equatable {
/// Equate two values of unknown type.
static func equate(_ any0: Any, _ any1: Any) -> Bool {
guard
let equatable0 = any0 as? Self,
let equatable1 = any1 as? Self
else { return false }
return equatable0 == equatable1
}
}
final class EquatableTestCase: XCTestCase {
func test_equate() {
let int: Any = Int.random( in: .min...(.max) )
let bool: Any = Bool.random()
XCTAssertTrue( Int.equate(int, int) )
XCTAssertTrue( .equate(bool, bool) )
XCTAssertFalse( .equate(int, int) )
XCTAssertTrue( AnyHashable.equate(bool, bool) )
XCTAssertFalse( AnyHashable.equate(bool, int) )
}
}
We can solve it in the following way
enum SwiftDataType
{
case String
case Int
case Int64
case Double
case Bool
case Undefined
}
func getType( of : Any ) -> SwiftDataType
{
if let type = of as? String
{
return SwiftDataType.String
}
else if let type = of as? Int
{
return SwiftDataType.Int
}
else if let type = of as? Int64
{
return SwiftDataType.Int64
}
else if let type = of as? Double
{
return SwiftDataType.Double
}
else if let type = of as? Bool
{
return SwiftDataType.Bool
}
else
{
return SwiftDataType.Undefined
}
}
func isEqual( a : Any, b : Any ) -> Bool
{
let aType : SwiftDataType = getType( of : a )
let bType : SwiftDataType = getType( of : b )
if aType != bType
{
print("Type is not Equal -> \(aType)")
return false
}
else
{
switch aType {
case SwiftDataType.String :
guard let aValue = a as? String, let bValue = b as? String else
{
return false
}
return aValue == bValue
case SwiftDataType.Int :
guard let aValue = a as? Int, let bValue = b as? Int else
{
return false
}
return aValue == bValue
case SwiftDataType.Int64 :
guard let aValue = a as? Int64, let bValue = b as? Int64 else
{
return false
}
return aValue == bValue
case SwiftDataType.Double :
guard let aValue = a as? Double, let bValue = b as? Double else
{
return false
}
return aValue == bValue
case SwiftDataType.Bool :
guard let aValue = a as? Bool, let bValue = b as? Bool else
{
return false
}
return aValue == bValue
default:
return false
}
}
}
You can use NSObject ...
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
var any5: Any? = nil
var any6: Any? = nil
print(any1 as? NSObject == any2 as? NSObject)
print(any2 as? NSObject == any3 as? NSObject)
print(any3 as? NSObject == any4 as? NSObject)
print(any4 as? NSObject == any5 as? NSObject)
print(any5 as? NSObject == any6 as? NSObject)
This should produce :-
true
false
true
false
true
There is a semi-private function _openExistential, shipped no later than Swift 5.6, that makes this possible.
First, consider the following utilities:
protocol EquatablePair {
func perform() -> Bool
}
protocol MaybeEquatablePair {
func maybePerform() -> Bool?
}
struct Pair<T> {
var lhs: T
var rhs: T
}
extension Pair: MaybeEquatablePair {
func maybePerform() -> Bool? {
(self as? EquatablePair)?.perform()
}
}
extension Pair: EquatablePair where T: Equatable {
func perform() -> Bool {
lhs == rhs
}
}
Here, we have a conditional conformance of Pair to EquatablePair. This allows us to use self as? EquatablePair to dynamically determine if T is Equatable. The MaybeEquatablePair conformance uses this trick to produce a boolean result if T is Equatable and nil otherwise.
The next part is to get Pair<T> for some concrete type T. We really need to get Pair<T> and not Pair<Any>. This is what helps me distinguish this subtle difference: Any is nothing but a struct of two fields, one being the pointer to the wrapped value’s type and the other the pointer to the actual value. The reality is slightly more complicated but this should give you some intuition. In this way, 1 as Int gives you a plain integer, where as (1 as Int) as Ayn gives you a special struct, hence Pair<Int> is very different from Pair<Any>.
So how can we dynamically fetch some Any’s wrapped value’s type and use that to get a desired Pair<T>? Here comes _openExisential:
func genericEqual(_ lhs: Any, _ rhs: Any) -> Bool {
func openLHS<LHS>(_ lhs: LHS) -> Bool {
if let rhs = rhs as? LHS {
return Pair(lhs: lhs, rhs: rhs).maybePerform() ?? false
} else {
return false
}
}
return _openExistential(lhs, do: openLHS)
}
_openExisential takes a wrapped value and use it to call some generic function. This magic function will dynamically fetch the type for its first argument and use that to call the generic function dynamically. This is not possible using plain Swift, in which calls to generic functions must have types resolved statically.
_openExisential can do more than Any. You might have heard the term existential types. This function can, well, open existential containers. It is a very complicated topic. See the Swift Evolution proposal Implicitly Opened Exisentials if you are interested.
My code is simplified from Foundation’s implementation for AttributedString. They seem to have a set of utilities to call Equatable, Encodable, Decodable implementation for Anys. Check out AttributedString.swift and AttributedStringAttribute.swift for more. Start with struct CheckEqualityIfEquatable.

KVC Swift 2.1 Reflection

I'm attempting to implement a KVC equivalent is Swift (inspired by David Owens) using reflection.
valueForKey is fairly trivial, using reflection to get all the children names and retrieve the appropriate value. setValueForKey has proved to be quite tricky however, as Swift reflection appears to be read-only (since readwrite would break reflections dogma)
protocol KVC {
var codeables: [String: Any.Type] { get }
mutating func setValue<T>(value: T, forKey key: String)
func getValue<T>(key: String) -> T?
}
extension KVC {
var codeables: [String: Any.Type] {
var dictionary: [String: Any.Type] = [:]
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if let label = child.label {
dictionary[label] = Mirror(reflecting: child.value).subjectType
}
}
return dictionary
}
mutating func setValue<T>(value: T, forKey key: String) {
if let valueType = self.codeables[key] where valueType == value.dynamicType {
}
}
func getValue<T>(key: String) -> T? {
let mirror = Mirror(reflecting: self)
for child in mirror.children {
if let label = child.label, value = child.value as? T where label == key {
return value
}
}
return nil
}
}
Is there anyway in Swift at all to set a dynamic keypath value without using the Objective-C runtime or enforcing that the conformer is a subclass of NSObject? It seems like the answer is no but there are some clever workarounds such as ObjectMapper, although I'm not a fan of the responsibility its on the conformer.