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
}
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]()
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)
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.
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.