Swift generic bool casting different from direct casting - swift

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)

Related

Cannot convert return expression of type '[Favorite.Type]' to return type '[Favorite]'

I want to make a general function for getting Elements from UserDefaults that are conforming to the NSObject and NSCoding Protocol. But when I want to use that function I get this error
func getFavorites() -> [Favorite] {
return get(type: Favorite, forKey: UD_FAVORITES)
}
Cannot convert return expression of type '[Favorite.Type]' to return type '[Favorite]'
That's my UserDefaults Extension:
func get<T>(type: T, forKey key: String) -> [T] {
if let data = self.object(forKey: key) as? Data {
do {
let tData = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [T]
return tData
} catch {
debugPrint(error)
return [T]()
}
} else {
print("EMPTY \(key)")
return [T]()
}
}
The type of type must be T.Type
func get<T>(type: T.Type, forKey key: String) -> [T] { ...
and you have to call it
return get(type: Favorite.self, forKey: UD_FAVORITES)
Actually you don't need the parameter, this is Swift, the compiler can infer the type (specified by the return type [Favorite])
func get<T>(valueForKey key: String) -> [T] {
and
return get(valueForKey: UD_FAVORITES)
And there is
if let data = self.data(forKey: key) {

Using key of a dictionary on another dictionary crashes

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

How can you check if a type is Optional in Swift?

How can you check if a type is Optional in Swift?
Say I have a variable of type PartialKeyPath where:
struct Foo {
let bar: String
let baz: String?
}
typealias Property<Root> = (key: PartialKeyPath<Root>, value: Any?)
typealias Properties<Root> = [Property<Root>]
Now say I iterate thru an instance of Properties:
properties.forEach { prop in
let valueType1 = type(of: prop.key).valueType
let valueType2 = type(of: value)
...
How can I check here whether valueType1 is Optional<valueType2>, or whether it is Optional of any other flavor for that matter?
So far the only way I’ve found is really ugly...
Using a similar approach to Optional field type doesn't conform protocol in Swift 3, you could define a 'dummy protocol' for Optional and use this to get the wrapped metatype:
protocol OptionalProtocol {
// the metatype value for the wrapped type.
static var wrappedType: Any.Type { get }
}
extension Optional : OptionalProtocol {
static var wrappedType: Any.Type { return Wrapped.self }
}
If you just want to know a type is an optional:
func isOptionalType(_ type: Any.Type) -> Bool {
return type is OptionalProtocol.Type
}
print(isOptionalType(String.self)) // false
print(isOptionalType(String?.self)) // true
If you want to check if one metatype is the 'optional version' of another metatype:
struct Foo {
let bar: String
let baz: String?
}
struct Property<Root> {
var key: PartialKeyPath<Root>
var value: Any
}
let properties = [Property(key: \Foo.baz, value: "hello")]
/// Attempt to get the `Wrapped` metatype from a metatype of an
/// `Optional<Wrapped>`. If not an `Optional`, will return `nil`.
func wrappedTypeFromOptionalType(_ type: Any.Type) -> Any.Type? {
return (type as? OptionalProtocol.Type)?.wrappedType
}
for property in properties {
let valueType1 = type(of: property.key).valueType
let valueType2 = type(of: property.value)
if wrappedTypeFromOptionalType(valueType1) == valueType2 {
print("\(valueType1) == Optional<\(valueType2)>")
}
}
// Optional<String> == Optional<String>
However there's almost certainly a better way to do whatever you're trying to do here with the key paths.
could you use a mirror reflecting Any and check displayStyle is optional?.
func isOptional(any:Any) -> Bool {
let mirror = Mirror(reflecting: any)
if mirror.displayStyle == .Optional {
return true
} else {
return false
}
}
More on mirror display style:
https://developer.apple.com/documentation/swift/mirror.displaystyle
This is a hacky but working solution:
func isOptional(_ type: Any.Type) -> Bool {
let typeName = String(describing: type)
return typeName.hasPrefix("Optional<")
}
Test:
let t1 = Int?.self
let t2 = Bool.self
print(isOptional(t1))
// true
print(isOptional(t2))
// false
A tweak of #kelin’s answer:
postfix operator ...?!
postfix func ...?!<T>(_ instance: T) -> Bool {
let subject = "\(Mirror(reflecting: instance).subjectType)"
return !subject.hasPrefix("Optional")
}
And in the vein of #Ercell0’s answer is this superior method:
func isOptional<T>(_ instance: T) -> Bool {
guard let displayStyle = Mirror(reflecting: instance).displayStyle
else { return false }
return displayStyle == .optional
}

Swift abstract return type of method

I wanna to create a function that returns a value an array from the UserDefauts, like this:
func GetBool(name: String) -> Bool {
let defaults = UserDefaults.standard
return defaults.bool(forKey: name)
}
func GetBoolArray(name: String) -> [Bool] {
let defaults = UserDefaults.standard
return defaults.array(forKey: name) as? [Bool] ?? [Bool]()
}
But I don't wanna create a function for Bool, another for Int, another for CGFloat, etc.
What's the best way to abstract all functions (for Bool, Int, etc.) into one (one for single values, other for array values)?
Would something like this work for you?
func GetValue(name: String) -> Any? {
let defaults = UserDefaults.standard
return defaults.value(forKey: name)
}
func GetValueArray(name: String) -> [Any] {
let defaults = UserDefaults.standard
return defaults.array(forKey: name) ?? [Any]()
}
Note that the first function needs to be unwrapped when used because the key you used might not match a value.
Also, I believe array for key works with NSArrays only so the first function would probably work for both cases for you.
Thanks to #Martin R, I discovered swift generics, this is what I was looking for
func GetValue<T>(name: String) -> T {
let defaults = UserDefaults.standard
return defaults.value(forKey: name) as! T
}
func GetArray<T>(name: String) -> [T] {
let defaults = UserDefaults.standard
return defaults.array(forKey: name) as? [T] ?? [T]()
}

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.